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

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/ghodss/yaml"
	"github.com/russross/blackfriday/v2"
)

// golang flags don't accept arrays by default. This adds it.
type flagStrings []string

func (flagString *flagStrings) String() string {
	return strings.Join(*flagString, ",")
}

func (flagString *flagStrings) Set(value string) error {
	*flagString = append(*flagString, value)
	return nil
}

func main() {
	var oldBranch, newBranch, templatesDir, outDir, oldRelease, newRelease, pullRequest string
	var validateOnly bool
	var notesDirs flagStrings

	flag.StringVar(&oldBranch, "oldBranch", "a", "branch to compare against")
	flag.StringVar(&newBranch, "newBranch", "b", "branch containing new files")
	flag.StringVar(&pullRequest, "pullRequest", "", "the pull request to check. Either this or oldBranch & newBranch are required.")
	flag.Var(&notesDirs, "notes", "the directory containing release notes. Repeat for multiple notes directories")
	flag.StringVar(&templatesDir, "templates", "./templates", "the directory containing release note templates")
	flag.StringVar(&outDir, "outDir", ".", "the directory containing release notes")
	flag.BoolVar(&validateOnly, "validateOnly", false, "set to true to perform validation only")
	flag.StringVar(&oldRelease, "oldRelease", "x.y.(z-1)", "old release")
	flag.StringVar(&newRelease, "newRelease", "x.y.z", "new release")
	flag.Parse()

	var releaseNotes []Note
	for _, notesDir := range notesDirs {
		var releaseNoteFiles []string

		fmt.Printf("Looking for release notes in %s.\n", notesDir)

		releaseNotesDir := "releasenotes/notes"
		if _, err := os.Stat(notesDir); os.IsNotExist(err) {
			fmt.Printf("Could not find repository -- directory %s does not exist.", notesDir)
			os.Exit(1)
		}

		if _, err := os.Stat(filepath.Join(notesDir, releaseNotesDir)); os.IsNotExist(err) {
			fmt.Printf("could not find release notes directory -- %s does not exist", filepath.Join(notesDir, releaseNotesDir))
			os.Exit(2)
		}

		var err error
		releaseNoteFiles, err = getNewFilesInBranch(oldBranch, newBranch, pullRequest, notesDir, releaseNotesDir)
		if err != nil {
			fmt.Fprintf(os.Stderr, "failed to list files: %s\n", err.Error())
			os.Exit(1)
		}
		fmt.Printf("Found %d files.\n\n", len(releaseNoteFiles))

		fmt.Printf("Parsing release notes\n")
		releaseNotesEntries, err := parseReleaseNotesFiles(notesDir, releaseNoteFiles)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Unable to read release notes: %s\n", err.Error())
			os.Exit(1)
		}
		releaseNotes = append(releaseNotes, releaseNotesEntries...)
	}

	if len(releaseNotes) < 1 {
		fmt.Fprintf(os.Stderr, "failed to find any release notes.\n")
		// maps to EX_NOINPUT, but more importantly lets us differentiate between no files found and other errors
		os.Exit(66)
	}

	if validateOnly {
		return
	}

	fmt.Printf("\nLooking for markdown templates in %s.\n", templatesDir)
	templateFiles, err := getFilesWithExtension(templatesDir, "md")
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to list files: %s\n", err.Error())
		os.Exit(1)
	}
	fmt.Printf("Found %d files.\n\n", len(templateFiles))

	for _, filename := range templateFiles {
		output, err := populateTemplate(templatesDir, filename, releaseNotes, oldRelease, newRelease)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to parse template: %s\n", err.Error())
			os.Exit(1)
		}

		if err := createDirIfNotExists(outDir); err != nil {
			fmt.Fprintf(os.Stderr, "Failed to create our dir: %s\n", err.Error())
		}
		if err := writeAsMarkdown(path.Join(outDir, filename), output); err != nil {
			fmt.Fprintf(os.Stderr, "Failed to write markdown: %s\n", err.Error())
		} else {
			fmt.Printf("Wrote markdown to %s\n", filename)
		}

		if err := writeAsHTML(path.Join(outDir, filename), output); err != nil {
			fmt.Fprintf(os.Stderr, "Failed to write HTML: %s\n", err.Error())
		} else {
			fmt.Printf("Wrote markdown to %s.html\n", filename)
		}
	}
}

func createDirIfNotExists(path string) error {
	err := os.MkdirAll(path, 0755)
	if os.IsExist(err) {
		return nil
	}
	return err
}

// writeAsHTML generates HTML from markdown before writing it to a file
func writeAsHTML(filename string, markdown string) error {
	output := string(blackfriday.Run([]byte(markdown)))
	if err := ioutil.WriteFile(filename+".html", []byte(output), 0644); err != nil {
		return err
	}
	return nil
}

// writeAsMarkdown writes markdown to a file
func writeAsMarkdown(filename string, markdown string) error {
	if err := ioutil.WriteFile(filename, []byte(markdown), 0644); err != nil {
		return err
	}
	return nil
}

func parseTemplateFormat(releaseNotes []Note, format string) ([]string, error) {
	template, err := ParseTemplate(format)
	if err != nil {
		return nil, fmt.Errorf("failed to parse template: %s", err.Error())
	}
	return getNotesForTemplateFormat(releaseNotes, template), nil
}

func getNotesForTemplateFormat(notes []Note, template Template) []string {
	parsedNotes := make([]string, 0)

	for _, note := range notes {
		if template.Type == "releaseNotes" {
			parsedNotes = append(parsedNotes, note.getReleaseNotes(template.Kind, template.Area, template.Action)...)
		} else if template.Type == "upgradeNotes" {
			parsedNotes = append(parsedNotes, note.getUpgradeNotes()...)
		} else if template.Type == "securityNotes" {
			parsedNotes = append(parsedNotes, note.getSecurityNotes()...)
		}
	}
	return parsedNotes
}

// getFilesWithExtension returns the files from filePath with extension extension
func getFilesWithExtension(filePath string, extension string) ([]string, error) {
	directory, err := os.Open(filePath)
	if err != nil {
		return nil, fmt.Errorf("failed to open directory: %s", err.Error())
	}
	defer directory.Close()

	var files []string
	files, err = directory.Readdirnames(0)
	if err != nil {
		return nil, fmt.Errorf("unable to list files for directory %s: %s", filePath, err.Error())
	}

	filesWithExtension := make([]string, 0)
	for _, fileName := range files {
		if strings.HasSuffix(fileName, extension) {
			filesWithExtension = append(filesWithExtension, fileName)
		}
	}

	return filesWithExtension, nil
}

func parseReleaseNotesFiles(filePath string, files []string) ([]Note, error) {
	notes := make([]Note, 0)
	for _, file := range files {
		file = path.Join(filePath, file)
		contents, err := ioutil.ReadFile(file)
		if err != nil {
			return nil, fmt.Errorf("unable to open file %s: %s", file, err.Error())
		}

		var note Note
		if err = yaml.Unmarshal(contents, &note); err != nil {
			return nil, fmt.Errorf("unable to parse release note %s:%s", file, err.Error())
		}
		note.File = file
		notes = append(notes, note)
		fmt.Printf("found %d upgrade notes, %d release notes, and %d security notes in %s\n", len(note.UpgradeNotes),
			len(note.ReleaseNotes), len(note.SecurityNotes), note.File)

	}
	return notes, nil
}

func populateTemplate(filepath string, filename string, releaseNotes []Note, oldRelease string, newRelease string) (string, error) {
	filename = path.Join(filepath, filename)
	fmt.Printf("Processing %s\n", filename)

	contents, err := ioutil.ReadFile(filename)
	if err != nil {
		return "", fmt.Errorf("unable to open file %s: %s", filename, err.Error())
	}

	comment := regexp.MustCompile("<!--(.*)-->")
	output := string(contents)

	output = strings.Replace(output, "<!--oldRelease-->", oldRelease, -1)
	output = strings.Replace(output, "<!--newRelease-->", newRelease, -1)

	results := comment.FindAllString(output, -1)

	for _, result := range results {
		contents, err := parseTemplateFormat(releaseNotes, result)
		if err != nil {
			return "", fmt.Errorf("unable to parse templates: %s", err.Error())
		}
		joinedContents := strings.Join(contents, "\n")
		output = strings.Replace(output, result, joinedContents, -1)
	}

	return output, nil
}

type prView struct {
	Files []struct {
		Path string `json:"path"`
	} `json:"files"`
}

func getFilesFromGHPRView(path string, pullRequest string, notesSubpath string) ([]string, error) {
	cmd := fmt.Sprintf("cd %s; gh pr view %s --json files", path, pullRequest)
	fmt.Printf("Executing: %s\n", cmd)
	out, err := exec.Command("bash", "-c", cmd).CombinedOutput()
	if err != nil {
		return nil, fmt.Errorf("received error running GH: %s", err.Error())
	}

	var prResults prView
	if err := json.Unmarshal(out, &prResults); err != nil {
		return nil, fmt.Errorf("failed to parse GH results: %s", err.Error())
	}

	var results []string
	for _, val := range prResults.Files {
		if strings.Contains(val.Path, notesSubpath) {
			results = append(results, val.Path)
		}
	}

	return results, nil
}

func getNewFilesInBranch(oldBranch string, newBranch string, pullRequest string, path string, notesSubpath string) ([]string, error) {
	// if there's a pull request, we can just get the changed files from GitHub. If not, we have to do it manually.
	if pullRequest != "" {
		return getFilesFromGHPRView(path, pullRequest, notesSubpath)
	}

	cmd := fmt.Sprintf("cd %s; git diff-tree -r --diff-filter=AMR --name-only --relative=%s '%s' '%s'", path, notesSubpath, oldBranch, newBranch)
	fmt.Printf("Executing: %s\n", cmd)
	out, err := exec.Command("bash", "-c", cmd).CombinedOutput()
	if err != nil {
		return nil, err
	}
	outFiles := strings.Split(string(out), "\n")

	return outFiles[:len(outFiles)-1], nil
}
<commit_msg>Pass ENV to gh (#1653)<commit_after>// Copyright 2020 Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/ghodss/yaml"
	"github.com/russross/blackfriday/v2"
)

// golang flags don't accept arrays by default. This adds it.
type flagStrings []string

func (flagString *flagStrings) String() string {
	return strings.Join(*flagString, ",")
}

func (flagString *flagStrings) Set(value string) error {
	*flagString = append(*flagString, value)
	return nil
}

func main() {
	var oldBranch, newBranch, templatesDir, outDir, oldRelease, newRelease, pullRequest string
	var validateOnly bool
	var notesDirs flagStrings

	flag.StringVar(&oldBranch, "oldBranch", "a", "branch to compare against")
	flag.StringVar(&newBranch, "newBranch", "b", "branch containing new files")
	flag.StringVar(&pullRequest, "pullRequest", "", "the pull request to check. Either this or oldBranch & newBranch are required.")
	flag.Var(&notesDirs, "notes", "the directory containing release notes. Repeat for multiple notes directories")
	flag.StringVar(&templatesDir, "templates", "./templates", "the directory containing release note templates")
	flag.StringVar(&outDir, "outDir", ".", "the directory containing release notes")
	flag.BoolVar(&validateOnly, "validateOnly", false, "set to true to perform validation only")
	flag.StringVar(&oldRelease, "oldRelease", "x.y.(z-1)", "old release")
	flag.StringVar(&newRelease, "newRelease", "x.y.z", "new release")
	flag.Parse()

	var releaseNotes []Note
	for _, notesDir := range notesDirs {
		var releaseNoteFiles []string

		fmt.Printf("Looking for release notes in %s.\n", notesDir)

		releaseNotesDir := "releasenotes/notes"
		if _, err := os.Stat(notesDir); os.IsNotExist(err) {
			fmt.Printf("Could not find repository -- directory %s does not exist.", notesDir)
			os.Exit(1)
		}

		if _, err := os.Stat(filepath.Join(notesDir, releaseNotesDir)); os.IsNotExist(err) {
			fmt.Printf("could not find release notes directory -- %s does not exist", filepath.Join(notesDir, releaseNotesDir))
			os.Exit(2)
		}

		var err error
		releaseNoteFiles, err = getNewFilesInBranch(oldBranch, newBranch, pullRequest, notesDir, releaseNotesDir)
		if err != nil {
			fmt.Fprintf(os.Stderr, "failed to list files: %s\n", err.Error())
			os.Exit(1)
		}
		fmt.Printf("Found %d files.\n\n", len(releaseNoteFiles))

		fmt.Printf("Parsing release notes\n")
		releaseNotesEntries, err := parseReleaseNotesFiles(notesDir, releaseNoteFiles)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Unable to read release notes: %s\n", err.Error())
			os.Exit(1)
		}
		releaseNotes = append(releaseNotes, releaseNotesEntries...)
	}

	if len(releaseNotes) < 1 {
		fmt.Fprintf(os.Stderr, "failed to find any release notes.\n")
		// maps to EX_NOINPUT, but more importantly lets us differentiate between no files found and other errors
		os.Exit(66)
	}

	if validateOnly {
		return
	}

	fmt.Printf("\nLooking for markdown templates in %s.\n", templatesDir)
	templateFiles, err := getFilesWithExtension(templatesDir, "md")
	if err != nil {
		fmt.Fprintf(os.Stderr, "failed to list files: %s\n", err.Error())
		os.Exit(1)
	}
	fmt.Printf("Found %d files.\n\n", len(templateFiles))

	for _, filename := range templateFiles {
		output, err := populateTemplate(templatesDir, filename, releaseNotes, oldRelease, newRelease)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to parse template: %s\n", err.Error())
			os.Exit(1)
		}

		if err := createDirIfNotExists(outDir); err != nil {
			fmt.Fprintf(os.Stderr, "Failed to create our dir: %s\n", err.Error())
		}
		if err := writeAsMarkdown(path.Join(outDir, filename), output); err != nil {
			fmt.Fprintf(os.Stderr, "Failed to write markdown: %s\n", err.Error())
		} else {
			fmt.Printf("Wrote markdown to %s\n", filename)
		}

		if err := writeAsHTML(path.Join(outDir, filename), output); err != nil {
			fmt.Fprintf(os.Stderr, "Failed to write HTML: %s\n", err.Error())
		} else {
			fmt.Printf("Wrote markdown to %s.html\n", filename)
		}
	}
}

func createDirIfNotExists(path string) error {
	err := os.MkdirAll(path, 0755)
	if os.IsExist(err) {
		return nil
	}
	return err
}

// writeAsHTML generates HTML from markdown before writing it to a file
func writeAsHTML(filename string, markdown string) error {
	output := string(blackfriday.Run([]byte(markdown)))
	if err := ioutil.WriteFile(filename+".html", []byte(output), 0644); err != nil {
		return err
	}
	return nil
}

// writeAsMarkdown writes markdown to a file
func writeAsMarkdown(filename string, markdown string) error {
	if err := ioutil.WriteFile(filename, []byte(markdown), 0644); err != nil {
		return err
	}
	return nil
}

func parseTemplateFormat(releaseNotes []Note, format string) ([]string, error) {
	template, err := ParseTemplate(format)
	if err != nil {
		return nil, fmt.Errorf("failed to parse template: %s", err.Error())
	}
	return getNotesForTemplateFormat(releaseNotes, template), nil
}

func getNotesForTemplateFormat(notes []Note, template Template) []string {
	parsedNotes := make([]string, 0)

	for _, note := range notes {
		if template.Type == "releaseNotes" {
			parsedNotes = append(parsedNotes, note.getReleaseNotes(template.Kind, template.Area, template.Action)...)
		} else if template.Type == "upgradeNotes" {
			parsedNotes = append(parsedNotes, note.getUpgradeNotes()...)
		} else if template.Type == "securityNotes" {
			parsedNotes = append(parsedNotes, note.getSecurityNotes()...)
		}
	}
	return parsedNotes
}

// getFilesWithExtension returns the files from filePath with extension extension
func getFilesWithExtension(filePath string, extension string) ([]string, error) {
	directory, err := os.Open(filePath)
	if err != nil {
		return nil, fmt.Errorf("failed to open directory: %s", err.Error())
	}
	defer directory.Close()

	var files []string
	files, err = directory.Readdirnames(0)
	if err != nil {
		return nil, fmt.Errorf("unable to list files for directory %s: %s", filePath, err.Error())
	}

	filesWithExtension := make([]string, 0)
	for _, fileName := range files {
		if strings.HasSuffix(fileName, extension) {
			filesWithExtension = append(filesWithExtension, fileName)
		}
	}

	return filesWithExtension, nil
}

func parseReleaseNotesFiles(filePath string, files []string) ([]Note, error) {
	notes := make([]Note, 0)
	for _, file := range files {
		file = path.Join(filePath, file)
		contents, err := ioutil.ReadFile(file)
		if err != nil {
			return nil, fmt.Errorf("unable to open file %s: %s", file, err.Error())
		}

		var note Note
		if err = yaml.Unmarshal(contents, &note); err != nil {
			return nil, fmt.Errorf("unable to parse release note %s:%s", file, err.Error())
		}
		note.File = file
		notes = append(notes, note)
		fmt.Printf("found %d upgrade notes, %d release notes, and %d security notes in %s\n", len(note.UpgradeNotes),
			len(note.ReleaseNotes), len(note.SecurityNotes), note.File)

	}
	return notes, nil
}

func populateTemplate(filepath string, filename string, releaseNotes []Note, oldRelease string, newRelease string) (string, error) {
	filename = path.Join(filepath, filename)
	fmt.Printf("Processing %s\n", filename)

	contents, err := ioutil.ReadFile(filename)
	if err != nil {
		return "", fmt.Errorf("unable to open file %s: %s", filename, err.Error())
	}

	comment := regexp.MustCompile("<!--(.*)-->")
	output := string(contents)

	output = strings.Replace(output, "<!--oldRelease-->", oldRelease, -1)
	output = strings.Replace(output, "<!--newRelease-->", newRelease, -1)

	results := comment.FindAllString(output, -1)

	for _, result := range results {
		contents, err := parseTemplateFormat(releaseNotes, result)
		if err != nil {
			return "", fmt.Errorf("unable to parse templates: %s", err.Error())
		}
		joinedContents := strings.Join(contents, "\n")
		output = strings.Replace(output, result, joinedContents, -1)
	}

	return output, nil
}

type prView struct {
	Files []struct {
		Path string `json:"path"`
	} `json:"files"`
}

func getFilesFromGHPRView(path string, pullRequest string, notesSubpath string) ([]string, error) {
	cmdStr := fmt.Sprintf("cd %s; gh pr view %s --json files", path, pullRequest)
	fmt.Printf("Executing: %s\n", cmdStr)

	cmd := exec.Command("bash", "-c", cmdStr)
	cmd.Env = os.Environ()
	out, err := cmd.CombinedOutput()
	fmt.Printf("%s\n", out)
	if err != nil {
		return nil, fmt.Errorf("received error running GH: %s", err.Error())
	}

	var prResults prView
	if err := json.Unmarshal(out, &prResults); err != nil {
		return nil, fmt.Errorf("failed to parse GH results: %s", err.Error())
	}

	var results []string
	for _, val := range prResults.Files {
		if strings.Contains(val.Path, notesSubpath) {
			results = append(results, val.Path)
		}
	}

	return results, nil
}

func getNewFilesInBranch(oldBranch string, newBranch string, pullRequest string, path string, notesSubpath string) ([]string, error) {
	// if there's a pull request, we can just get the changed files from GitHub. If not, we have to do it manually.
	if pullRequest != "" {
		return getFilesFromGHPRView(path, pullRequest, notesSubpath)
	}

	cmd := fmt.Sprintf("cd %s; git diff-tree -r --diff-filter=AMR --name-only --relative=%s '%s' '%s'", path, notesSubpath, oldBranch, newBranch)
	fmt.Printf("Executing: %s\n", cmd)
	out, err := exec.Command("bash", "-c", cmd).CombinedOutput()
	if err != nil {
		return nil, err
	}
	outFiles := strings.Split(string(out), "\n")

	return outFiles[:len(outFiles)-1], nil
}
<|endoftext|>


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

package space_test

import (
	"github.com/juju/errors"
	"github.com/juju/testing"
	jc "github.com/juju/testing/checkers"
	gc "gopkg.in/check.v1"

	"github.com/juju/juju/cmd/juju/space"
	coretesting "github.com/juju/juju/testing"
)

type RemoveSuite struct {
	BaseSpaceSuite
}

var _ = gc.Suite(&RemoveSuite{})

func (s *RemoveSuite) SetUpTest(c *gc.C) {
	s.BaseSpaceSuite.SetUpTest(c)
	s.command = space.NewRemoveCommand(s.api)
	c.Assert(s.command, gc.NotNil)
}

func (s *RemoveSuite) TestInit(c *gc.C) {
	for i, test := range []struct {
		about      string
		args       []string
		expectName string
		expectErr  string
	}{{
		about:     "no arguments",
		expectErr: "Space name is required",
	}, {
		about:     "invalid space name - with invalid characters",
		args:      s.Strings("%inv$alid"),
		expectErr: `"%inv\$alid" is not a valid space name`,
	}, {
		about:     "invalid space name - using underscores",
		args:      s.Strings("42_space"),
		expectErr: `"42_space" is not a valid space name`,
	}, {
		about:     "multiple space names aren't allowed",
		args:      s.Strings("a-space", "another-space"),
		expectErr: "Please only provide a single space name.",
	}, {
		about:      "delete a valid space name",
		args:       s.Strings("myspace"),
		expectName: "myspace",
	}} {
		c.Logf("test #%d: %s", i, test.about)
		// Create a new instance of the subcommand for each test, but
		// since we're not running the command no need to use
		// envcmd.Wrap().
		command := space.NewRemoveCommand(s.api)
		err := coretesting.InitCommand(command, test.args)
		if test.expectErr != "" {
			c.Check(err, gc.ErrorMatches, test.expectErr)
		} else {
			c.Check(err, jc.ErrorIsNil)
		}
		c.Check(command.Name, gc.Equals, test.expectName)
		// No API calls should be recorded at this stage.
		s.api.CheckCallNames(c)
	}
}

func (s *RemoveSuite) TestRunValidSpaceSucceeds(c *gc.C) {
	stdout, stderr, err := s.RunSubCommand(c, "myspace")
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(stdout, gc.Equals, "")
	c.Assert(stderr, gc.Matches, `removed space "myspace"\n`)
	s.api.CheckCalls(c, []testing.StubCall{{
		FuncName: "RemoveSpace",
		Args:     []interface{}{"myspace"},
	}, {
		FuncName: "Close",
		Args:     nil,
	}})
}

func (s *RemoveSuite) TestRunWithNonExistentSpaceFails(c *gc.C) {
	s.api.SetErrors(errors.NotFoundf("space %q", "foo"))

	stdout, stderr, err := s.RunSubCommand(c, "foo")
	c.Assert(err, gc.ErrorMatches, `cannot remove space "foo": space "foo" not found`)
	c.Assert(err, jc.Satisfies, errors.IsNotFound)
	c.Assert(stdout, gc.Equals, "")
	c.Assert(stderr, gc.Equals, "")
	s.api.CheckCallNames(c, "RemoveSpace", "Close")
}

func (s *RemoveSuite) TestRunAPIConnectFails(c *gc.C) {
	// TODO(dimitern): Change this once API is implemented.
	s.command = space.NewCreateCommand(nil)
	stdout, stderr, err := s.RunSubCommand(c, "myspace")
	c.Assert(err, gc.ErrorMatches, "cannot connect to API server: API not implemented yet!")
	c.Assert(stdout, gc.Equals, "")
	c.Assert(stderr, gc.Equals, "")
	// No API calls recoreded.
	s.api.CheckCallNames(c)
}
<commit_msg>Test fixes<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package space_test

import (
	"github.com/juju/errors"
	"github.com/juju/testing"
	jc "github.com/juju/testing/checkers"
	gc "gopkg.in/check.v1"

	"github.com/juju/juju/cmd/juju/space"
	coretesting "github.com/juju/juju/testing"
)

type RemoveSuite struct {
	BaseSpaceSuite
}

var _ = gc.Suite(&RemoveSuite{})

func (s *RemoveSuite) SetUpTest(c *gc.C) {
	s.BaseSpaceSuite.SetUpTest(c)
	s.command = space.NewRemoveCommand(s.api)
	c.Assert(s.command, gc.NotNil)
}

func (s *RemoveSuite) TestInit(c *gc.C) {
	for i, test := range []struct {
		about      string
		args       []string
		expectName string
		expectErr  string
	}{{
		about:     "no arguments",
		expectErr: "space name is required",
	}, {
		about:     "invalid space name - with invalid characters",
		args:      s.Strings("%inv$alid"),
		expectErr: `"%inv\$alid" is not a valid space name`,
	}, {
		about:     "invalid space name - using underscores",
		args:      s.Strings("42_space"),
		expectErr: `"42_space" is not a valid space name`,
	}, {
		about:     "multiple space names aren't allowed",
		args:      s.Strings("a-space", "another-space"),
		expectErr: "please only provide a single space name.",
	}, {
		about:      "delete a valid space name",
		args:       s.Strings("myspace"),
		expectName: "myspace",
	}} {
		c.Logf("test #%d: %s", i, test.about)
		// Create a new instance of the subcommand for each test, but
		// since we're not running the command no need to use
		// envcmd.Wrap().
		command := space.NewRemoveCommand(s.api)
		err := coretesting.InitCommand(command, test.args)
		if test.expectErr != "" {
			c.Check(err, gc.ErrorMatches, test.expectErr)
		} else {
			c.Check(err, jc.ErrorIsNil)
		}
		c.Check(command.Name, gc.Equals, test.expectName)
		// No API calls should be recorded at this stage.
		s.api.CheckCallNames(c)
	}
}

func (s *RemoveSuite) TestRunValidSpaceSucceeds(c *gc.C) {
	stdout, stderr, err := s.RunSubCommand(c, "myspace")
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(stdout, gc.Equals, "")
	c.Assert(stderr, gc.Matches, `removed space "myspace"\n`)
	s.api.CheckCalls(c, []testing.StubCall{{
		FuncName: "RemoveSpace",
		Args:     []interface{}{"myspace"},
	}, {
		FuncName: "Close",
		Args:     nil,
	}})
}

func (s *RemoveSuite) TestRunWithNonExistentSpaceFails(c *gc.C) {
	s.api.SetErrors(errors.NotFoundf("space %q", "foo"))

	stdout, stderr, err := s.RunSubCommand(c, "foo")
	c.Assert(err, gc.ErrorMatches, `cannot remove space "foo": space "foo" not found`)
	c.Assert(err, jc.Satisfies, errors.IsNotFound)
	c.Assert(stdout, gc.Equals, "")
	c.Assert(stderr, gc.Equals, "")
	s.api.CheckCallNames(c, "RemoveSpace", "Close")
}

func (s *RemoveSuite) TestRunAPIConnectFails(c *gc.C) {
	// TODO(dimitern): Change this once API is implemented.
	s.command = space.NewCreateCommand(nil)
	stdout, stderr, err := s.RunSubCommand(c, "myspace")
	c.Assert(err, gc.ErrorMatches, "cannot connect to API server: API not implemented yet!")
	c.Assert(stdout, gc.Equals, "")
	c.Assert(stderr, gc.Equals, "")
	// No API calls recoreded.
	s.api.CheckCallNames(c)
}
<|endoftext|>


<commit_before>package pf

func isPowerOfFour(num int) bool {
	return useLoops(num)
}

func useLoops(num int) bool {
	if num <= 0 {
		return false
	}
	for num != 1 {
		if num%4 != 0 {
			return false
		}
		num >>= 2
	}
	return true
}
<commit_msg>solve 342 using precomputing<commit_after>package pf

func isPowerOfFour(num int) bool {
	// return useLoops(num)
	return preCompute(num)
}

// useLoops time complexity O(lgN), space complexity O(1)
func useLoops(num int) bool {
	if num <= 0 {
		return false
	}
	for num != 1 {
		if num%4 != 0 {
			return false
		}
		num >>= 2
	}
	return true
}

var results map[int]bool

func init() {
	if results == nil {
		results = make(map[int]bool)
	}
	// since num <= 2^31 - 1, so the max power of 4 is 4^15
	results[1] = true
	base := 1
	for i := 1; i <= 15; i++ {
		base *= 4
		results[base] = true
	}
}

// preCompute time complexity O(1), space complexity O(1)
func preCompute(num int) bool {
	return results[num]
}
<|endoftext|>


<commit_before>package ams

import (
	"context"
	"net/http"

	"github.com/pkg/errors"
)

const (
	assetsEndpoint = "Assets"
)

const (
	OptionStorageEncrypted = 1 << iota
	OptionCommonEncryptionProtected
	OptionEnvelopeEncryptionProtected
	OptionNone = 0
)

const (
	StateInitialized = iota
	StatePublished   // The 'Publish' action has been deprecated. Remove the code that checks whether an asset is in the 'Published' state.
	StateDeleted
)

const (
	FormatOptionNoFormat          = 0
	FormatOptionAdaptiveStreaming = 1
)

type Asset struct {
	ID                 string `json:"Id"`
	State              int    `json:"State"`
	Created            string `json:"Created"`
	LastModified       string `json:"LastModified"`
	Name               string `json:"Name"`
	Options            int    `json:"Options"`
	FormatOption       int    `json:"FormatOption"`
	URI                string `json:"Uri"`
	StorageAccountName string `json:"StorageAccountName"`
}

func (c *Client) GetAsset(ctx context.Context, assetID string) (*Asset, error) {
	endpoint := toAssetResource(assetID)
	req, err := c.newRequest(ctx, http.MethodGet, endpoint)
	if err != nil {
		return nil, errors.Wrap(err, "request build failed")
	}

	c.logger.Printf("[INFO] get asset #%s ...", assetID)
	var out Asset
	if err := c.do(req, http.StatusOK, &out); err != nil {
		return nil, errors.Wrap(err, "request failed")
	}
	c.logger.Printf("[INFO] completed")
	return &out, nil
}

func (c *Client) GetAssets(ctx context.Context) ([]Asset, error) {
	req, err := c.newRequest(ctx, http.MethodGet, assetsEndpoint)
	if err != nil {
		return nil, errors.Wrap(err, "request build failed")
	}
	c.logger.Printf("[INFO] get assets ...")
	var out struct {
		Assets []Asset `json:"value"`
	}
	if err := c.do(req, http.StatusOK, &out); err != nil {
		return nil, errors.Wrap(err, "request failed")
	}
	c.logger.Printf("[INFO] completed")
	return out.Assets, nil
}

func (c *Client) CreateAsset(ctx context.Context, name string) (*Asset, error) {
	params := map[string]interface{}{
		"Name": name,
	}
	req, err := c.newRequest(ctx, http.MethodPost, assetsEndpoint, withJSON(params))
	if err != nil {
		return nil, errors.Wrap(err, "request build failed")
	}
	c.logger.Printf("[INFO] create asset [name=%#v] ...", name)
	var out Asset
	if err := c.do(req, http.StatusCreated, &out); err != nil {
		return nil, errors.Wrap(err, "request failed")
	}
	c.logger.Printf("[INFO] completed, new asset[#%s]", out.ID)
	return &out, nil
}

func (c *Client) GetAssetFiles(ctx context.Context, assetID string) ([]AssetFile, error) {
	endpoint := toAssetResource(assetID) + "/Files"
	req, err := c.newRequest(ctx, http.MethodGet, endpoint)
	if err != nil {
		return nil, errors.Wrap(err, "request build failed")
	}

	c.logger.Printf("[INFO] get asset[#%s] files ...", assetID)
	var out struct {
		AssetFiles []AssetFile `json:"value"`
	}
	if err := c.do(req, http.StatusOK, &out); err != nil {
		return nil, errors.Wrap(err, "request failed")
	}
	c.logger.Printf("[INFO] completed")
	return out.AssetFiles, nil
}

func (c *Client) DeleteAsset(ctx context.Context, assetID string) error {
	endpoint := toAssetResource(assetID)
	req, err := c.newRequest(ctx, http.MethodDelete, endpoint)
	if err != nil {
		return errors.Wrap(err, "request build failed")
	}

	c.logger.Printf("[INFO] delete asset[#%s] ...")
	if err := c.do(req, http.StatusNoContent, nil); err != nil {
		return errors.Wrap(err, "request failed")
	}
	c.logger.Printf("[INFO] completed")
	return nil
}

func toAssetResource(assetID string) string {
	return toResource(assetsEndpoint, assetID)
}

func (c *Client) buildAssetURI(assetID string) string {
	return c.buildURI(toResource(assetsEndpoint, assetID))
}
<commit_msg>refactor: use path.Join<commit_after>package ams

import (
	"context"
	"net/http"
	"path"

	"github.com/pkg/errors"
)

const (
	assetsEndpoint = "Assets"
)

const (
	OptionStorageEncrypted = 1 << iota
	OptionCommonEncryptionProtected
	OptionEnvelopeEncryptionProtected
	OptionNone = 0
)

const (
	StateInitialized = iota
	StatePublished   // The 'Publish' action has been deprecated. Remove the code that checks whether an asset is in the 'Published' state.
	StateDeleted
)

const (
	FormatOptionNoFormat          = 0
	FormatOptionAdaptiveStreaming = 1
)

type Asset struct {
	ID                 string `json:"Id"`
	State              int    `json:"State"`
	Created            string `json:"Created"`
	LastModified       string `json:"LastModified"`
	Name               string `json:"Name"`
	Options            int    `json:"Options"`
	FormatOption       int    `json:"FormatOption"`
	URI                string `json:"Uri"`
	StorageAccountName string `json:"StorageAccountName"`
}

func (c *Client) GetAsset(ctx context.Context, assetID string) (*Asset, error) {
	endpoint := toAssetResource(assetID)
	req, err := c.newRequest(ctx, http.MethodGet, endpoint)
	if err != nil {
		return nil, errors.Wrap(err, "request build failed")
	}

	c.logger.Printf("[INFO] get asset #%s ...", assetID)
	var out Asset
	if err := c.do(req, http.StatusOK, &out); err != nil {
		return nil, errors.Wrap(err, "request failed")
	}
	c.logger.Printf("[INFO] completed")
	return &out, nil
}

func (c *Client) GetAssets(ctx context.Context) ([]Asset, error) {
	req, err := c.newRequest(ctx, http.MethodGet, assetsEndpoint)
	if err != nil {
		return nil, errors.Wrap(err, "request build failed")
	}
	c.logger.Printf("[INFO] get assets ...")
	var out struct {
		Assets []Asset `json:"value"`
	}
	if err := c.do(req, http.StatusOK, &out); err != nil {
		return nil, errors.Wrap(err, "request failed")
	}
	c.logger.Printf("[INFO] completed")
	return out.Assets, nil
}

func (c *Client) CreateAsset(ctx context.Context, name string) (*Asset, error) {
	params := map[string]interface{}{
		"Name": name,
	}
	req, err := c.newRequest(ctx, http.MethodPost, assetsEndpoint, withJSON(params))
	if err != nil {
		return nil, errors.Wrap(err, "request build failed")
	}
	c.logger.Printf("[INFO] create asset [name=%#v] ...", name)
	var out Asset
	if err := c.do(req, http.StatusCreated, &out); err != nil {
		return nil, errors.Wrap(err, "request failed")
	}
	c.logger.Printf("[INFO] completed, new asset[#%s]", out.ID)
	return &out, nil
}

func (c *Client) GetAssetFiles(ctx context.Context, assetID string) ([]AssetFile, error) {
	endpoint := path.Join(toAssetResource(assetID), filesEndpoint)
	req, err := c.newRequest(ctx, http.MethodGet, endpoint)
	if err != nil {
		return nil, errors.Wrap(err, "request build failed")
	}

	c.logger.Printf("[INFO] get asset[#%s] files ...", assetID)
	var out struct {
		AssetFiles []AssetFile `json:"value"`
	}
	if err := c.do(req, http.StatusOK, &out); err != nil {
		return nil, errors.Wrap(err, "request failed")
	}
	c.logger.Printf("[INFO] completed")
	return out.AssetFiles, nil
}

func (c *Client) DeleteAsset(ctx context.Context, assetID string) error {
	endpoint := toAssetResource(assetID)
	req, err := c.newRequest(ctx, http.MethodDelete, endpoint)
	if err != nil {
		return errors.Wrap(err, "request build failed")
	}

	c.logger.Printf("[INFO] delete asset[#%s] ...")
	if err := c.do(req, http.StatusNoContent, nil); err != nil {
		return errors.Wrap(err, "request failed")
	}
	c.logger.Printf("[INFO] completed")
	return nil
}

func toAssetResource(assetID string) string {
	return toResource(assetsEndpoint, assetID)
}

func (c *Client) buildAssetURI(assetID string) string {
	return c.buildURI(toAssetResource(assetID))
}
<|endoftext|>


<commit_before>package async

import (
	"errors"
	"fmt"
	"sync"
	"time"
)

type Method func(args ...interface{}) (interface{}, error)
type LambdaMethod func() (interface{}, error)

var panicHandler func(interface{})

func SetPanicHandler(hanlder func(interface{})) {
	panicHandler = hanlder
}

func Safety(method func() (interface{}, error)) (res interface{}, err error) {
	defer func() {
		if e := recover(); e != nil {
			_, ok := e.(error)
			if ok {
				err = e.(error)
			} else {
				err = errors.New(fmt.Sprintf("%v", e))
			}
			if panicHandler != nil {
				panicHandler(err)
			}
		}
	}()
	return method()
}

func Retry(method func()(interface{}, error), maxCount int, interval time.Duration) (interface{}, error) {
	count := 0
	for {
		res, err := Lambda(method, 0)
		if err == nil {
			return res, err
		}
		count = count + 1
		if count >= maxCount {
			return nil, err
		}
		<-time.After(interval)
	}
}

func Lambda(method func() (interface{}, error), timeout time.Duration) (interface{}, error) {
	output := make(chan interface{})
	go func() {
		defer close(output)
		defer func() {
			if e := recover(); e != nil {
				err := errors.New(fmt.Sprintf("%s", e))
				if panicHandler != nil {
					panicHandler(err)
				}
				output <- err
			}
		}()
		res, err := method()
		if err != nil {
			output <- err
		} else {
			output <- res
		}
	}()
	if timeout > 0 {
		timer := time.NewTimer(timeout)
		defer timer.Stop()
		select {
		case res := <-output:
			{
				switch err := res.(type) {
				case error:
					{
						return nil, err
					}
				default:
					{
						return res, nil
					}
				}
			}
		case <-timer.C:
			{
				return nil, errors.New("Async_Timeout")
			}
		}
	} else {
		res := <-output
		switch err := res.(type) {
		case error:
			{
				return nil, err
			}
		default:
			{
				return res, nil
			}
		}
	}
}

func Call(m Method, timeout time.Duration, args ...interface{}) (interface{}, error) {
	return Lambda(func() (interface{}, error) {
		return m(args...)
	}, timeout)
}

func All(methods []LambdaMethod, timeout time.Duration) []interface{} {
	var wg sync.WaitGroup
	result := make([]interface{}, len(methods))
	for i, m := range methods {
		wg.Add(1)
		go func(index int, method LambdaMethod) {
			defer wg.Done()
			res, err := Lambda(method, timeout)
			if err != nil {
				result[index] = err
			} else {
				result[index] = res
			}
		}(i, m)
	}
	wg.Wait()
	return result
}

func Serise(methods []LambdaMethod, timeout time.Duration) []interface{} {
	result := make([]interface{}, 0)
	for _, m := range methods {
		res, err := Lambda(m, timeout)
		if err != nil {
			result = append(result, err)
			return result
		} else {
			result = append(result, res)
		}
	}
	return result
}

func Flow(enter Method, args []interface{}, methods []Method, timeout time.Duration) (interface{}, error) {
	var (
		res interface{}
		err error
	)
	res, err = Call(enter, timeout, args...)
	if err != nil {
		return nil, err
	}
	for _, m := range methods {
		res, err = Call(m, timeout, res)
		if err != nil {
			return nil, err
		}
	}
	return res, nil
}

func Any(methods []LambdaMethod, timeout time.Duration) ([]interface{}, error) {
	resChan := make(chan []interface{}, 1)
	errChan := make(chan error, len(methods))
	go func() {
		defer func() {
			close(resChan)
			close(errChan)
		}()
		var wg sync.WaitGroup
		result := make([]interface{}, len(methods))
		for i, m := range methods {
			wg.Add(1)
			go func(index int, method LambdaMethod) {
				defer wg.Done()
				res, err := Lambda(method, timeout)
				if err != nil {
					errChan <- err
				} else {
					result[index] = res
				}
			}(i, m)
		}
		wg.Wait()
		resChan <- result
	}()
	select {
	case err := <-errChan:
		return nil, err
	case res := <-resChan:
		return res, nil
	}
}

func AnyOne(methods []LambdaMethod, timeout time.Duration) (interface{}, []error) {
	resChan := make(chan interface{}, len(methods))
	errChan := make(chan []error)
	go func() {
		defer func() {
			close(resChan)
			close(errChan)
		}()
		var wg sync.WaitGroup
		errs := make([]error, len(methods))
		for i, m := range methods {
			wg.Add(1)
			go func(index int, method LambdaMethod) {
				defer wg.Done()
				res, err := Lambda(method, timeout)
				if err != nil {
					errs[index] = err
				} else {
					resChan <- res
				}
			}(i, m)
		}
		wg.Wait()
		errChan <- errs
	}()
	select {
	case errs := <-errChan:
		return nil, errs
	case res := <-resChan:
		return res, nil
	}
}

func Parallel(methods []LambdaMethod, maxCount int) []interface{} {
	if maxCount <= 0 {
		maxCount = 1
	}
	var wg sync.WaitGroup
	workers := make(chan bool, maxCount)
	for i := 0; i < maxCount; i++ {
		workers <- true
	}
	results := make([]interface{}, len(methods))
	for index, method := range methods {
		<-workers
		wg.Add(1)
		go func(i int, m LambdaMethod) {
			defer func() {
				workers <- true
				wg.Done()
			}()
			res, err := Lambda(m, 0)
			if err != nil {
				results[i] = err
			} else {
				results[i] = res
			}
		}(index, method)
	}
	wg.Wait()
	close(workers)
	return results
}
<commit_msg>add foreach for slice<commit_after>package async

import (
	"errors"
	"fmt"
	"sync"
	"time"
)

type Method func(args ...interface{}) (interface{}, error)
type LambdaMethod func() (interface{}, error)

var panicHandler func(interface{})

func SetPanicHandler(hanlder func(interface{})) {
	panicHandler = hanlder
}

func Safety(method func() (interface{}, error)) (res interface{}, err error) {
	defer func() {
		if e := recover(); e != nil {
			_, ok := e.(error)
			if ok {
				err = e.(error)
			} else {
				err = errors.New(fmt.Sprintf("%v", e))
			}
			if panicHandler != nil {
				panicHandler(err)
			}
		}
	}()
	return method()
}

func Retry(method func()(interface{}, error), maxCount int, interval time.Duration) (interface{}, error) {
	count := 0
	for {
		res, err := Lambda(method, 0)
		if err == nil {
			return res, err
		}
		count = count + 1
		if count >= maxCount {
			return nil, err
		}
		<-time.After(interval)
	}
}

func Lambda(method func() (interface{}, error), timeout time.Duration) (interface{}, error) {
	output := make(chan interface{})
	go func() {
		defer close(output)
		defer func() {
			if e := recover(); e != nil {
				err := errors.New(fmt.Sprintf("%s", e))
				if panicHandler != nil {
					panicHandler(err)
				}
				output <- err
			}
		}()
		res, err := method()
		if err != nil {
			output <- err
		} else {
			output <- res
		}
	}()
	if timeout > 0 {
		timer := time.NewTimer(timeout)
		defer timer.Stop()
		select {
		case res := <-output:
			{
				switch err := res.(type) {
				case error:
					{
						return nil, err
					}
				default:
					{
						return res, nil
					}
				}
			}
		case <-timer.C:
			{
				return nil, errors.New("Async_Timeout")
			}
		}
	} else {
		res := <-output
		switch err := res.(type) {
		case error:
			{
				return nil, err
			}
		default:
			{
				return res, nil
			}
		}
	}
}

func Call(m Method, timeout time.Duration, args ...interface{}) (interface{}, error) {
	return Lambda(func() (interface{}, error) {
		return m(args...)
	}, timeout)
}

func All(methods []LambdaMethod, timeout time.Duration) []interface{} {
	var wg sync.WaitGroup
	result := make([]interface{}, len(methods))
	for i, m := range methods {
		wg.Add(1)
		go func(index int, method LambdaMethod) {
			defer wg.Done()
			res, err := Lambda(method, timeout)
			if err != nil {
				result[index] = err
			} else {
				result[index] = res
			}
		}(i, m)
	}
	wg.Wait()
	return result
}

func Serise(methods []LambdaMethod, timeout time.Duration) []interface{} {
	result := make([]interface{}, 0)
	for _, m := range methods {
		res, err := Lambda(m, timeout)
		if err != nil {
			result = append(result, err)
			return result
		} else {
			result = append(result, res)
		}
	}
	return result
}

func Flow(enter Method, args []interface{}, methods []Method, timeout time.Duration) (interface{}, error) {
	var (
		res interface{}
		err error
	)
	res, err = Call(enter, timeout, args...)
	if err != nil {
		return nil, err
	}
	for _, m := range methods {
		res, err = Call(m, timeout, res)
		if err != nil {
			return nil, err
		}
	}
	return res, nil
}

func Any(methods []LambdaMethod, timeout time.Duration) ([]interface{}, error) {
	resChan := make(chan []interface{}, 1)
	errChan := make(chan error, len(methods))
	go func() {
		defer func() {
			close(resChan)
			close(errChan)
		}()
		var wg sync.WaitGroup
		result := make([]interface{}, len(methods))
		for i, m := range methods {
			wg.Add(1)
			go func(index int, method LambdaMethod) {
				defer wg.Done()
				res, err := Lambda(method, timeout)
				if err != nil {
					errChan <- err
				} else {
					result[index] = res
				}
			}(i, m)
		}
		wg.Wait()
		resChan <- result
	}()
	select {
	case err := <-errChan:
		return nil, err
	case res := <-resChan:
		return res, nil
	}
}

func AnyOne(methods []LambdaMethod, timeout time.Duration) (interface{}, []error) {
	resChan := make(chan interface{}, len(methods))
	errChan := make(chan []error)
	go func() {
		defer func() {
			close(resChan)
			close(errChan)
		}()
		var wg sync.WaitGroup
		errs := make([]error, len(methods))
		for i, m := range methods {
			wg.Add(1)
			go func(index int, method LambdaMethod) {
				defer wg.Done()
				res, err := Lambda(method, timeout)
				if err != nil {
					errs[index] = err
				} else {
					resChan <- res
				}
			}(i, m)
		}
		wg.Wait()
		errChan <- errs
	}()
	select {
	case errs := <-errChan:
		return nil, errs
	case res := <-resChan:
		return res, nil
	}
}

func Parallel(methods []LambdaMethod, maxCount int) []interface{} {
	if maxCount <= 0 {
		maxCount = 1
	}
	var wg sync.WaitGroup
	workers := make(chan bool, maxCount)
	for i := 0; i < maxCount; i++ {
		workers <- true
	}
	results := make([]interface{}, len(methods))
	for index, method := range methods {
		<-workers
		wg.Add(1)
		go func(i int, m LambdaMethod) {
			defer func() {
				workers <- true
				wg.Done()
			}()
			res, err := Lambda(m, 0)
			if err != nil {
				results[i] = err
			} else {
				results[i] = res
			}
		}(index, method)
	}
	wg.Wait()
	close(workers)
	return results
}

func Foreach(objs []interface{}, method func(int) (interface{}, error), maxCount int) []interface{} {
	if maxCount <= 0 {
		maxCount = 1
	}
	var wg sync.WaitGroup
	workers := make(chan bool, maxCount)
	for i := 0; i < maxCount; i++ {
		workers <- true
	}
	results := make([]interface{}, len(objs))
	for index, _ := range objs {
		<-workers
		wg.Add(1)
		go func(i int, method func(int) (interface{}, error)) {
			defer func() {
				workers <- true
				wg.Done()
			}()
			res, err := method(i)
			if err != nil {
				results[i] = err
			} else {
				results[i] = res
			}
		}(index, method)
	}
	wg.Wait()
	close(workers)
	return results
}<|endoftext|>


<commit_before>package catfacts

import (
	"fmt"
	"github.com/fabioxgn/go-bot"
	"github.com/fabioxgn/go-bot/web"
	"regexp"
)

const (
	pattern     = "(?i)\\b(%s)[s|z]{0,1}\\b"
	catFactsURL = "http://catfacts-api.appspot.com/api/facts?number=1"
	msgPrefix   = "I love cats! Here's a fact: %s"
)

type facts struct {
	Facts   []string `json:"facts"`
	Success string   `json:"success"`
}

var (
	catWords = []string{
		"cat",
		"gato",
		"miau",
		"meow",
		"garfield",
		"lolcat",
	}
)

func getFacts(text string, get web.GetJSONFunc) (string, error) {
	for _, s := range catWords {
		match, _ := regexp.MatchString(fmt.Sprintf(pattern, s), text)
		if match {
			return getFact(get)
		}
	}
	return "", nil
}

func getFact(get web.GetJSONFunc) (string, error) {
	data := &facts{}
	err := get(catFactsURL, data)
	if err != nil {
		return "", err
	}

	if len(data.Facts) == 0 {
		return "", nil
	}

	return fmt.Sprintf(msgPrefix, data.Facts[0]), nil
}

func catfacts(command *bot.PassiveCmd) (string, error) {
	return getFacts(command.Raw, web.GetJSON)
}

func init() {
	bot.RegisterPassiveCommand(
		"catfacts",
		catfacts)
}
<commit_msg>Refactor the catfacts command<commit_after>package catfacts

import (
	"fmt"
	"github.com/fabioxgn/go-bot"
	"github.com/fabioxgn/go-bot/web"
	"regexp"
)

const (
	pattern     = "(?i)\\b(cat|gato|miau|meow|garfield|lolcat)[s|z]{0,1}\\b"
	catFactsURL = "http://catfacts-api.appspot.com/api/facts?number=1"
	msgPrefix   = "I love cats! Here's a fact: %s"
)

type facts struct {
	Facts   []string `json:"facts"`
	Success string   `json:"success"`
}

var (
	re = regexp.MustCompile(pattern)
)

func getFacts(text string, get web.GetJSONFunc) (string, error) {
	if re.MatchString(text) {
		return getFact(get)
	}
	return "", nil
}

func getFact(get web.GetJSONFunc) (string, error) {
	data := &facts{}
	err := get(catFactsURL, data)
	if err != nil {
		return "", err
	}

	if len(data.Facts) == 0 {
		return "", nil
	}

	return fmt.Sprintf(msgPrefix, data.Facts[0]), nil
}

func catfacts(command *bot.PassiveCmd) (string, error) {
	return getFacts(command.Raw, web.GetJSON)
}

func init() {
	bot.RegisterPassiveCommand(
		"catfacts",
		catfacts)
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Intel Corporation
//
// 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 main

import (
	"fmt"
	"io/ioutil"
	"regexp"
	"strings"
	"testing"
	"time"

	"github.com/sirupsen/logrus"
	"github.com/stretchr/testify/assert"
)

type testData struct {
	network     string
	raddr       string
	expectError bool
}

func init() {
	// Ensure all log levels are logged
	ccLog.Logger.Level = logrus.DebugLevel

	// Discard log output
	ccLog.Logger.Out = ioutil.Discard
}

func TestHandleSystemLog(t *testing.T) {
	assert := assert.New(t)

	data := []testData{
		{"invalid-net-type", "999.999.999.999", true},
		{"invalid net-type", "a a ", true},
		{"invalid-net-type", ".", true},
		{"moo", "999.999.999.999", true},
		{"moo", "999.999.999.999:99999999999999999", true},
		{"qwerty", "uiop:ftw!", true},
		{"", "", false},
	}

	for _, d := range data {
		err := handleSystemLog(d.network, d.raddr)
		if d.expectError {
			assert.Error(err, fmt.Sprintf("%+v", d))
		} else {
			assert.NoError(err, fmt.Sprintf("%+v", d))
		}
	}
}

func TestNewSystemLogHook(t *testing.T) {
	assert := assert.New(t)

	hook, err := newSystemLogHook("", "")
	assert.NoError(err)

	msg := "wibble"
	level := logrus.DebugLevel

	logger := logrus.New()

	// ensure all output is displayed
	logger.Level = logrus.DebugLevel

	// throw away all stdout so that the Format() call
	// below returns the data in structured form.
	logger.Out = ioutil.Discard

	entry := &logrus.Entry{
		Logger: logger,

		// UTC for time.Parse()
		Time: time.Now().UTC(),

		Message: msg,
		Level:   level,
	}

	// call the formatting function directly and see if the output
	// matches what we expect.
	bytes, err := hook.formatter.Format(entry)
	assert.NoError(err)

	output := string(bytes)
	output = strings.TrimSpace(output)
	output = strings.Replace(output, `"`, "", -1)

	fields := strings.Fields(output)

	msgFound := ""
	timeFound := ""
	levelFound := ""

	// look for the expected fields
	for _, field := range fields {

		// split each structured field into name and value fields
		f := strings.Split(field, "=")
		assert.True(len(f) >= 2)

		switch f[0] {
		case "level":
			levelFound = f[1]
		case "msg":
			msgFound = f[1]
		case "time":
			timeFound = f[1]
		}
	}

	assert.Equal(levelFound, level.String())
	assert.Equal(msgFound, msg)
	assert.NotEqual(timeFound, "")

	// Tell time.Parse() how to handle the timestamps by putting it into
	// the standard golang time format equivalent to:
	//
	//     "Mon Jan 2 15:04:05 -0700 MST 2006".
	//
	expectedTimeFormat := "2006-01-02T15:04:05.999999999Z"

	// Note that time.Parse() assumes a UTC time.
	_, err = time.Parse(expectedTimeFormat, timeFound)
	assert.NoError(err)

	// time.Parse() is "clever" but also doesn't check anything more
	// granular than a second, so let's be completely paranoid and check
	// via regular expression too.
	expectedPattern :=
		// YYYY-MM-DD
		`\d{4}-\d{2}-\d{2}` +
			// time separator
			`T` +
			// HH:MM:SS
			`\d{2}:\d{2}:\d{2}` +
			// high-precision separator
			`.` +
			// nano-seconds
			`\d{9}` +
			// UTC timezone specifier
			`Z`

	expectedRE := regexp.MustCompile(expectedPattern)
	matched := expectedRE.FindAllStringSubmatch(timeFound, -1)
	assert.NotNil(matched, "expected time in format %q, got %q", expectedPattern, timeFound)
}
<commit_msg>logger: Fix nanosecond timestamp test<commit_after>// Copyright (c) 2017 Intel Corporation
//
// 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 main

import (
	"fmt"
	"io/ioutil"
	"regexp"
	"strings"
	"testing"
	"time"

	"github.com/sirupsen/logrus"
	"github.com/stretchr/testify/assert"
)

type testData struct {
	network     string
	raddr       string
	expectError bool
}

func init() {
	// Ensure all log levels are logged
	ccLog.Logger.Level = logrus.DebugLevel

	// Discard log output
	ccLog.Logger.Out = ioutil.Discard
}

func TestHandleSystemLog(t *testing.T) {
	assert := assert.New(t)

	data := []testData{
		{"invalid-net-type", "999.999.999.999", true},
		{"invalid net-type", "a a ", true},
		{"invalid-net-type", ".", true},
		{"moo", "999.999.999.999", true},
		{"moo", "999.999.999.999:99999999999999999", true},
		{"qwerty", "uiop:ftw!", true},
		{"", "", false},
	}

	for _, d := range data {
		err := handleSystemLog(d.network, d.raddr)
		if d.expectError {
			assert.Error(err, fmt.Sprintf("%+v", d))
		} else {
			assert.NoError(err, fmt.Sprintf("%+v", d))
		}
	}
}

func TestNewSystemLogHook(t *testing.T) {
	assert := assert.New(t)

	hook, err := newSystemLogHook("", "")
	assert.NoError(err)

	msg := "wibble"
	level := logrus.DebugLevel

	logger := logrus.New()

	// ensure all output is displayed
	logger.Level = logrus.DebugLevel

	// throw away all stdout so that the Format() call
	// below returns the data in structured form.
	logger.Out = ioutil.Discard

	entry := &logrus.Entry{
		Logger: logger,

		// UTC for time.Parse()
		Time: time.Now().UTC(),

		Message: msg,
		Level:   level,
	}

	// call the formatting function directly and see if the output
	// matches what we expect.
	bytes, err := hook.formatter.Format(entry)
	assert.NoError(err)

	output := string(bytes)
	output = strings.TrimSpace(output)
	output = strings.Replace(output, `"`, "", -1)

	fields := strings.Fields(output)

	msgFound := ""
	timeFound := ""
	levelFound := ""

	// look for the expected fields
	for _, field := range fields {

		// split each structured field into name and value fields
		f := strings.Split(field, "=")
		assert.True(len(f) >= 2)

		switch f[0] {
		case "level":
			levelFound = f[1]
		case "msg":
			msgFound = f[1]
		case "time":
			timeFound = f[1]
		}
	}

	assert.Equal(levelFound, level.String())
	assert.Equal(msgFound, msg)
	assert.NotEqual(timeFound, "")

	// Tell time.Parse() how to handle the timestamps by putting it into
	// the standard golang time format equivalent to:
	//
	//     "Mon Jan 2 15:04:05 -0700 MST 2006".
	//
	expectedTimeFormat := "2006-01-02T15:04:05.999999999Z"

	// Note that time.Parse() assumes a UTC time.
	_, err = time.Parse(expectedTimeFormat, timeFound)
	assert.NoError(err)

	// time.Parse() is "clever" but also doesn't check anything more
	// granular than a second, so let's be completely paranoid and check
	// via regular expression too.
	expectedPattern :=
		// YYYY-MM-DD
		`\d{4}-\d{2}-\d{2}` +
			// time separator
			`T` +
			// HH:MM:SS
			`\d{2}:\d{2}:\d{2}` +
			// high-precision separator
			`.` +
			// nano-seconds. Note that the quantifier range is
			// required because the time.RFC3339Nano format
			// trunctates trailing zeros.
			`\d{1,9}` +
			// UTC timezone specifier
			`Z`

	expectedRE := regexp.MustCompile(expectedPattern)
	matched := expectedRE.FindAllStringSubmatch(timeFound, -1)
	assert.NotNil(matched, "expected time in format %q, got %q", expectedPattern, timeFound)
}
<|endoftext|>


<commit_before>package logger

import (
	"bytes"
	"testing"
)

func TestGetLevel(t *testing.T) {
	n := New("logger.Test.GetLevel")

	n.Info(n, "Starting")
	m := make(map[Logger]Priority)
	m[""] = DefaultPriority
	m["."] = DefaultPriority
	m["Test"] = DefaultPriority
	m[".Test"] = DefaultPriority

	SetLevel("Test2", Emergency)
	m["Test2"] = Emergency
	m["Test2.Test"] = Emergency
	m["Test2.Test.Test"] = Emergency
	m["Test2.Test.Test.Test"] = Emergency
	m["Test2.Test.Test.Test.Test"] = Emergency
	m["Test2.Test.Test.Test.Test.Test"] = Emergency

	for k, v := range m {
		o := GetLevel(k)
		if o != v {
			n.Error(n, "GOT: '", o, "', EXPECED: '", v, "'", ", KEY: '", k, "'")
			t.Fail()
		}
		n.Debug(n, "GOT: '", o, "', EXPECED: '", v, "'", ", KEY: '", k, "'")
	}
	n.Info(n, "Finished")
}

func TestgetParentLevel(t *testing.T) {
	n := New("logger.Test.getParentLevel")

	n.Info(n, "Starting")
	m := make(map[Logger]Priority)
	m["."] = DefaultPriority
	m["Test"] = DefaultPriority
	m["Test.Test"] = DefaultPriority

	SetLevel("Test2", Emergency)
	m["Test2"] = DefaultPriority
	m["Test2.Test"] = Emergency

	for k, v := range m {
		o := getParentLevel(k)
		if o != v {
			n.Error(n, "GOT: '", o, "', EXPECED: '", v, "'", ", KEY: '", k, "'")
			t.Fail()
		}
		n.Debug(n, "GOT: '", o, "', EXPECED: '", v, "'", ", KEY: '", k, "'")
	}
	n.Info(n, "Finished")
}

func TestgetParent(t *testing.T) {
	n := New("logger.Test.getParent")

	n.Info(n, "Starting")
	m := [][]Logger{
		{"", "."},
		{".Test", "."},
		{".", "."},
		{"Test", "."},
		{"Test.Test", "Test"},
		{"Test.Test.Test", "Test.Test"},
		{"Test.Test.Test.Test", "Test.Test.Test"},
	}

	for i := range m {
		a := m[i]

		k := a[0]
		v := a[1]

		o := getParent(k)
		if o != v {
			n.Error(n, "GOT: '", o, "', EXPECED: '", v, "'", ", KEY: '", k, "'")
			t.Fail()
		}
		n.Debug(n, "GOT: '", o, "', EXPECED: '", v, "'", ", KEY: '", k, "'")
	}
	n.Info(n, "Finished")
}

func TestprintMessage(t *testing.T) {
	n := New("logger.Test.printMessage")

	n.Info(n, "Starting")
	m := [][]string{
		{"", "Test - Debug - "},
		{"Test", "Test - Debug - Test"},
		{"Test.Test", "Test - Debug - Test.Test"},
		{"Test.Test.Test", "Test - Debug - Test.Test.Test"},
	}

	SetFormat("Test", "{{.Logger}} - {{.Priority}} - {{.Message}}")
	l := getLogger("Test")

	for i := range m {
		a := m[i]

		k := a[0]
		v := a[1]

		var b bytes.Buffer
		printMessage(l, Debug, &b, k)
		o := b.String()
		if o != v {
			n.Error(n, "GOT: '", o, "', EXPECED: '", v, "'", ", KEY: '", k, "'")
			t.Fail()
		}
		n.Debug(n, "GOT: '", o, "', EXPECED: '", v, "'", ", KEY: '", k, "'")
	}

	n.Info(n, "Finished")
}

func BenchmarkLogMRoot(b *testing.B) {
	for i := 0; i < b.N; i++ {
		Log(".", Debug, "Test")
	}
}

func BenchmarkLogMRootEmergency(b *testing.B) {
	for i := 0; i < b.N; i++ {
		Log(".", Emergency, "Test")
	}
}

func BenchmarkLogMChild(b *testing.B) {
	for i := 0; i < b.N; i++ {
		Log("BenchLogMChild", Debug, "Test")
	}
}

func BenchmarkLogMChildChild(b *testing.B) {
	for i := 0; i < b.N; i++ {
		Log("BenchLogMChildChild.Test", Debug, "Test")
	}
}

func BenchmarkLogMChildAllocated(b *testing.B) {
	SetLevel("BenchLogMChildAllocated", Emergency)
	for i := 0; i < b.N; i++ {
		Log("BenchLogMChildAllocated", Debug, "Test")
	}
}

func BenchmarkLogMChildChildAllocated(b *testing.B) {
	SetLevel("BenchLogMChildChildAllocated.Test", Emergency)
	for i := 0; i < b.N; i++ {
		Log("BenchLogMChildChildAllocated.Test", Debug, "Test")
	}
}

func BenchmarkGetParentRoot(b *testing.B) {
	for i := 0; i < b.N; i++ {
		getParent(".")
	}
}

func BenchmarkGetParentChild(b *testing.B) {
	for i := 0; i < b.N; i++ {
		getParent("BenchgetParentChild")
	}
}

func BenchmarkGetParentChildChild(b *testing.B) {
	for i := 0; i < b.N; i++ {
		getParent("BenchgetParentChildChild.Test")
	}
}

func BenchmarkGetParentChildChildChild(b *testing.B) {
	for i := 0; i < b.N; i++ {
		getParent("BenchgetParentChildChild.Test.Test")
	}
}

func BenchmarkGetParentChildChildChildChild(b *testing.B) {
	for i := 0; i < b.N; i++ {
		getParent("BenchgetParentChildChildChild.Test.Test")
	}
}

func BenchmarkGetParentChildChildChildChildChild(b *testing.B) {
	for i := 0; i < b.N; i++ {
		getParent("BenchgetParentChildChildChildChild.Test.Test.Test")
	}
}

func BenchmarkPrintMessage(b *testing.B) {
	var a bytes.Buffer
	l := getLogger("BenchprintMessage")

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		printMessage(l, Debug, &a, "Message")
	}
}

func BenchmarkFormatMessage(b *testing.B) {
	l := getLogger("BenchformatMessage")

	m := new(message)
	m.Time = "Mo 30 Sep 2013 20:29:19 CEST"
	m.Logger = l.Logger
	m.Priority = "Debug"
	m.Message = "Test"

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		formatMessage(m, l.Format)
	}
}
<commit_msg>Renamed tests to reflect namechanges of logger functions<commit_after>package logger

import (
	"bytes"
	"testing"
)

func TestGetLevel(t *testing.T) {
	n := New("logger.Test.GetLevel")

	n.Info(n, "Starting")
	m := make(map[Logger]Priority)
	m[""] = DefaultPriority
	m["."] = DefaultPriority
	m["Test"] = DefaultPriority
	m[".Test"] = DefaultPriority

	SetLevel("Test2", Emergency)
	m["Test2"] = Emergency
	m["Test2.Test"] = Emergency
	m["Test2.Test.Test"] = Emergency
	m["Test2.Test.Test.Test"] = Emergency
	m["Test2.Test.Test.Test.Test"] = Emergency
	m["Test2.Test.Test.Test.Test.Test"] = Emergency

	for k, v := range m {
		o := GetLevel(k)
		if o != v {
			n.Error(n, "GOT: '", o, "', EXPECED: '", v, "'", ", KEY: '", k, "'")
			t.Fail()
		}
		n.Debug(n, "GOT: '", o, "', EXPECED: '", v, "'", ", KEY: '", k, "'")
	}
	n.Info(n, "Finished")
}

func TestgetParentLevel(t *testing.T) {
	n := New("logger.Test.getParentLevel")

	n.Info(n, "Starting")
	m := make(map[Logger]Priority)
	m["."] = DefaultPriority
	m["Test"] = DefaultPriority
	m["Test.Test"] = DefaultPriority

	SetLevel("Test2", Emergency)
	m["Test2"] = DefaultPriority
	m["Test2.Test"] = Emergency

	for k, v := range m {
		o := getParentLevel(k)
		if o != v {
			n.Error(n, "GOT: '", o, "', EXPECED: '", v, "'", ", KEY: '", k, "'")
			t.Fail()
		}
		n.Debug(n, "GOT: '", o, "', EXPECED: '", v, "'", ", KEY: '", k, "'")
	}
	n.Info(n, "Finished")
}

func TestgetParent(t *testing.T) {
	n := New("logger.Test.getParent")

	n.Info(n, "Starting")
	m := [][]Logger{
		{"", "."},
		{".Test", "."},
		{".", "."},
		{"Test", "."},
		{"Test.Test", "Test"},
		{"Test.Test.Test", "Test.Test"},
		{"Test.Test.Test.Test", "Test.Test.Test"},
	}

	for i := range m {
		a := m[i]

		k := a[0]
		v := a[1]

		o := getParent(k)
		if o != v {
			n.Error(n, "GOT: '", o, "', EXPECED: '", v, "'", ", KEY: '", k, "'")
			t.Fail()
		}
		n.Debug(n, "GOT: '", o, "', EXPECED: '", v, "'", ", KEY: '", k, "'")
	}
	n.Info(n, "Finished")
}

func TestprintMessage(t *testing.T) {
	n := New("logger.Test.printMessage")

	n.Info(n, "Starting")
	m := [][]string{
		{"", "Test - Debug - "},
		{"Test", "Test - Debug - Test"},
		{"Test.Test", "Test - Debug - Test.Test"},
		{"Test.Test.Test", "Test - Debug - Test.Test.Test"},
	}

	SetFormat("Test", "{{.Logger}} - {{.Priority}} - {{.Message}}")
	l := getLogger("Test")

	for i := range m {
		a := m[i]

		k := a[0]
		v := a[1]

		var b bytes.Buffer
		printMessage(l, Debug, &b, k)
		o := b.String()
		if o != v {
			n.Error(n, "GOT: '", o, "', EXPECED: '", v, "'", ", KEY: '", k, "'")
			t.Fail()
		}
		n.Debug(n, "GOT: '", o, "', EXPECED: '", v, "'", ", KEY: '", k, "'")
	}

	n.Info(n, "Finished")
}

func BenchmarkLogRoot(b *testing.B) {
	for i := 0; i < b.N; i++ {
		Log(".", Debug, "Test")
	}
}

func BenchmarkLogRootEmergency(b *testing.B) {
	for i := 0; i < b.N; i++ {
		Log(".", Emergency, "Test")
	}
}

func BenchmarkLogChild(b *testing.B) {
	for i := 0; i < b.N; i++ {
		Log("BenchLogChild", Debug, "Test")
	}
}

func BenchmarkLogChildChild(b *testing.B) {
	for i := 0; i < b.N; i++ {
		Log("BenchLogChildChild.Test", Debug, "Test")
	}
}

func BenchmarkLogChildAllocated(b *testing.B) {
	SetLevel("BenchLogChildAllocated", Emergency)
	for i := 0; i < b.N; i++ {
		Log("BenchLogChildAllocated", Debug, "Test")
	}
}

func BenchmarkLogChildChildAllocated(b *testing.B) {
	SetLevel("BenchLogChildChildAllocated.Test", Emergency)
	for i := 0; i < b.N; i++ {
		Log("BenchLogChildChildAllocated.Test", Debug, "Test")
	}
}

func BenchmarkGetParentRoot(b *testing.B) {
	for i := 0; i < b.N; i++ {
		getParent(".")
	}
}

func BenchmarkGetParentChild(b *testing.B) {
	for i := 0; i < b.N; i++ {
		getParent("BenchgetParentChild")
	}
}

func BenchmarkGetParentChildChild(b *testing.B) {
	for i := 0; i < b.N; i++ {
		getParent("BenchgetParentChildChild.Test")
	}
}

func BenchmarkGetParentChildChildChild(b *testing.B) {
	for i := 0; i < b.N; i++ {
		getParent("BenchgetParentChildChild.Test.Test")
	}
}

func BenchmarkGetParentChildChildChildChild(b *testing.B) {
	for i := 0; i < b.N; i++ {
		getParent("BenchgetParentChildChildChild.Test.Test")
	}
}

func BenchmarkGetParentChildChildChildChildChild(b *testing.B) {
	for i := 0; i < b.N; i++ {
		getParent("BenchgetParentChildChildChildChild.Test.Test.Test")
	}
}

func BenchmarkPrintMessage(b *testing.B) {
	var a bytes.Buffer
	l := getLogger("BenchprintMessage")

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		printMessage(l, Debug, &a, "Message")
	}
}

func BenchmarkFormatMessage(b *testing.B) {
	l := getLogger("BenchformatMessage")

	m := new(message)
	m.Time = "Mo 30 Sep 2013 20:29:19 CEST"
	m.Logger = l.Logger
	m.Priority = "Debug"
	m.Message = "Test"

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		formatMessage(m, l.Format)
	}
}
<|endoftext|>


<commit_before>package logic

import (
	"fmt"
	"strings"

	"github.com/google/go-github/github"
	"github.com/nlopes/slack"
	"github.com/svera/snowden/config"
)

// Logic is a struct that contains all the code and properties needed to send a message to subscribers of files and folders
// of a specific repository.
type Logic struct {
	sender senderInterface
	gh     githubInterface
	cfg    *config.Config
}

// New returns a new instance of Logic.
func New(sender senderInterface, gh githubInterface, cfg *config.Config) *Logic {
	return &Logic{
		sender: sender,
		gh:     gh,
		cfg:    cfg,
	}
}

// Process will, given an owner of a repository, its name and a PR number, alert subscriber about a new PR being opened if
// it affects any of their watched files or folders.
func (l *Logic) Process(action string, owner string, repo string, number int, title string, description string) error {
	var err error

	if _, ok := l.cfg.Watched[repo]; !ok {
		return nil
	}

	if action != "opened" && action != "reopened" {
		return nil
	}

	var subs []string
	if files, _, err := l.gh.ListFiles(owner, repo, number, &github.ListOptions{}); err == nil {
		for _, file := range files {
			l.appendSubscribers(&subs, file.Filename, l.cfg.Watched[repo], owner)
		}
		if len(subs) > 0 {
			if err = l.notify(subs, owner, repo, number, title, description); err != nil {
				return err
			}
		}
		return nil
	}
	return err
}

func (l *Logic) appendSubscribers(subs *[]string, fileName *string, rules []config.Rule, owner string) {
	for _, rule := range rules {
		for _, exception := range rule.Exceptions {
			if exception == owner {
				return
			}
		}
		for _, name := range rule.Names {
			if strings.HasPrefix(*fileName, name) {
				for _, new := range rule.Subscribers {
					l.appendIfNotIn(subs, new)
				}
			}
		}
	}
}

func (l *Logic) appendIfNotIn(subs *[]string, subscriber string) {
	for _, v := range *subs {
		if v == subscriber {
			return
		}
	}
	*subs = append(*subs, subscriber)
}

func (l *Logic) notify(subs []string, owner string, repo string, number int, title string, description string) error {
	url := fmt.Sprintf("https://github.com/%s/%s/pull/%d", owner, repo, number)
	for _, subscriber := range subs {
		params := slack.PostMessageParameters{
			Markdown: true,
		}
		attachment := slack.Attachment{
			Fields: []slack.AttachmentField{
				slack.AttachmentField{
					Title: title,
					Value: description,
				},
			},
		}
		params.Attachments = []slack.Attachment{attachment}
		_, _, err := l.sender.PostMessage(
			subscriber,
			fmt.Sprintf("Psssst... *%s* has opened a PR %s that affects files watched by you!", owner, url),
			params,
		)
		if err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>Improved message presentation<commit_after>package logic

import (
	"fmt"
	"strings"

	"github.com/google/go-github/github"
	"github.com/nlopes/slack"
	"github.com/svera/snowden/config"
)

// Logic is a struct that contains all the code and properties needed to send a message to subscribers of files and folders
// of a specific repository.
type Logic struct {
	sender senderInterface
	gh     githubInterface
	cfg    *config.Config
}

// New returns a new instance of Logic.
func New(sender senderInterface, gh githubInterface, cfg *config.Config) *Logic {
	return &Logic{
		sender: sender,
		gh:     gh,
		cfg:    cfg,
	}
}

// Process will, given an owner of a repository, its name and a PR number, alert subscriber about a new PR being opened if
// it affects any of their watched files or folders.
func (l *Logic) Process(action string, owner string, repo string, number int, title string, description string) error {
	var err error

	if _, ok := l.cfg.Watched[repo]; !ok {
		return nil
	}

	if action != "opened" && action != "reopened" {
		return nil
	}

	var subs []string
	if files, _, err := l.gh.ListFiles(owner, repo, number, &github.ListOptions{}); err == nil {
		for _, file := range files {
			l.appendSubscribers(&subs, file.Filename, l.cfg.Watched[repo], owner)
		}
		if len(subs) > 0 {
			if err = l.notify(subs, owner, repo, number, title, description); err != nil {
				return err
			}
		}
		return nil
	}
	return err
}

func (l *Logic) appendSubscribers(subs *[]string, fileName *string, rules []config.Rule, owner string) {
	for _, rule := range rules {
		for _, exception := range rule.Exceptions {
			if exception == owner {
				return
			}
		}
		for _, name := range rule.Names {
			if strings.HasPrefix(*fileName, name) {
				for _, new := range rule.Subscribers {
					l.appendIfNotIn(subs, new)
				}
			}
		}
	}
}

func (l *Logic) appendIfNotIn(subs *[]string, subscriber string) {
	for _, v := range *subs {
		if v == subscriber {
			return
		}
	}
	*subs = append(*subs, subscriber)
}

func (l *Logic) notify(subs []string, owner string, repo string, number int, title string, description string) error {
	url := fmt.Sprintf("https://github.com/%s/%s/pull/%d", owner, repo, number)
	for _, subscriber := range subs {
		params := slack.PostMessageParameters{
			Markdown: true,
		}
		attachment := slack.Attachment{
			Title:     title,
			TitleLink: url,
			Text:      description,
		}
		params.Attachments = []slack.Attachment{attachment}
		_, _, err := l.sender.PostMessage(
			subscriber,
			fmt.Sprintf("Psssst... *%s* has opened a PR that affects files watched by you!", owner),
			params,
		)
		if err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package login

import (
	"net/http"
	"encoding/json"
	"log"
	"strings"

	"github.com/dgrijalva/jwt-go"
)

type LoginResponse struct {
	Type 	string
	Message string
	Name 	string
}

type UserSafe struct {
	Name      string `json:"name"`
	Status 		string `json:"status"`
	Connections int    `json:"connections"`
}

type User struct {
    Name      string `json:"name"`
    Password	string `json:"password"`
    Token		string `json:"token"`
}

type UserList struct {
	List []User
	SafeList []UserSafe
}

func Api(data *UserList, w http.ResponseWriter, r *http.Request, mySigningKey []byte, mode string){
	var u User

	if r.Body == nil {
		http.Error(w, "Please send a request body", 400)
		return
	}
	err := json.NewDecoder(r.Body).Decode(&u)
	if err != nil {
		http.Error(w, err.Error(), 400)
		return
	}
	if strings.TrimSpace(u.Name) == "" || strings.TrimSpace(u.Password) == "" {
		if mode == "Debug" {
			log.Println("User submitted only whitespace for username and/or password")
		}
		sendErrorResponse(w, "Username / Password cannot consist of whitespace characters")
		return
	}

	for i := range data.List {
		if data.List[i].Name == u.Name {
			if data.List[i].Password != u.Password {
				if mode == "Debug" {
					log.Println("Invalid submission attempt for account:", data.List[i].Name)
				}
				sendErrorResponse(w, "Password is not correct for this user account")
				return
			} else {
				if mode == "Debug" {
					log.Println("Successful login via API for account:", u.Name)
				}
				sendSuccessResponse(w, data.List[i])
				return
			}
		}
	}
	// MARKER Server -> A new client is registering with server
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
	    "id": u.Name,
	})

	tokenString, err := token.SignedString(mySigningKey)
	if err != nil {
		log.Fatal(err)
	}
	u.Token = tokenString
	data.List = append(data.List, u)
	var uSafe UserSafe
	uSafe.Name = u.Name
	uSafe.Status = "Offline"
	uSafe.Connections = 0
	data.SafeList = append(data.SafeList, uSafe)
	if mode == "Debug" {
		log.Println("Successful login via API for account:", u.Name)
	}
	sendSuccessResponse(w, u)
}

func sendSuccessResponse(w http.ResponseWriter, u User){
	var res LoginResponse
	res.Type = "Success"
	res.Name = u.Name
	res.Message = u.Token
	json.NewEncoder(w).Encode(res)
}

func sendErrorResponse(w http.ResponseWriter, message string){
	var err LoginResponse
	err.Type = "Error"
	err.Message = message
	json.NewEncoder(w).Encode(err)
}<commit_msg>Add an admin field which defaults to false on all created users<commit_after>package login

import (
	"net/http"
	"encoding/json"
	"log"
	"strings"

	"github.com/dgrijalva/jwt-go"
)

type LoginResponse struct {
	Type 	string
	Message string
	Name 	string
}

type UserSafe struct {
	Name      string `json:"name"`
	Status 		string `json:"status"`
	Connections int    `json:"connections"`
}

type User struct {
    Name      string `json:"name"`
    Password	string `json:"password"`
    Token		string `json:"token"`
    Admin		bool   `json: "-"`
}

type UserList struct {
	List []User
	SafeList []UserSafe
}

func Api(data *UserList, w http.ResponseWriter, r *http.Request, mySigningKey []byte, mode string){
	var u User

	if r.Body == nil {
		http.Error(w, "Please send a request body", 400)
		return
	}
	err := json.NewDecoder(r.Body).Decode(&u)
	if err != nil {
		http.Error(w, err.Error(), 400)
		return
	}
	if strings.TrimSpace(u.Name) == "" || strings.TrimSpace(u.Password) == "" {
		if mode == "Debug" {
			log.Println("User submitted only whitespace for username and/or password")
		}
		sendErrorResponse(w, "Username / Password cannot consist of whitespace characters")
		return
	}

	for i := range data.List {
		if data.List[i].Name == u.Name {
			if data.List[i].Password != u.Password {
				if mode == "Debug" {
					log.Println("Invalid submission attempt for account:", data.List[i].Name)
				}
				sendErrorResponse(w, "Password is not correct for this user account")
				return
			} else {
				if mode == "Debug" {
					log.Println("Successful login via API for account:", u.Name)
				}
				sendSuccessResponse(w, data.List[i])
				return
			}
		}
	}
	// MARKER Server -> A new client is registering with server
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
	    "id": u.Name,
	})

	tokenString, err := token.SignedString(mySigningKey)
	if err != nil {
		log.Fatal(err)
	}
	u.Token = tokenString
	u.Admin = false
	data.List = append(data.List, u)
	var uSafe UserSafe
	uSafe.Name = u.Name
	uSafe.Status = "Offline"
	uSafe.Connections = 0
	data.SafeList = append(data.SafeList, uSafe)
	if mode == "Debug" {
		log.Println("Successful login via API for account:", u.Name)
	}
	sendSuccessResponse(w, u)
}

func sendSuccessResponse(w http.ResponseWriter, u User){
	var res LoginResponse
	res.Type = "Success"
	res.Name = u.Name
	res.Message = u.Token
	json.NewEncoder(w).Encode(res)
}

func sendErrorResponse(w http.ResponseWriter, message string){
	var err LoginResponse
	err.Type = "Error"
	err.Message = message
	json.NewEncoder(w).Encode(err)
}<|endoftext|>


<commit_before>//go:build js
// +build js

package os

import (
	"errors"
	_ "unsafe" // for go:linkname

	"github.com/gopherjs/gopherjs/js"
)

const isBigEndian = false

func runtime_args() []string { // not called on Windows
	return Args
}

func init() {
	if process := js.Global.Get("process"); process != js.Undefined {
		argv := process.Get("argv")
		Args = make([]string, argv.Length()-1)
		for i := 0; i < argv.Length()-1; i++ {
			Args[i] = argv.Index(i + 1).String()
		}
	}
	if len(Args) == 0 {
		Args = []string{"?"}
	}
}

func runtime_beforeExit() {}

func executable() (string, error) {
	return "", errors.New("Executable not implemented for GOARCH=js")
}

//go:linkname fastrand runtime.fastrand
func fastrand() uint32
<commit_msg>Work around undefined process.argv<commit_after>//go:build js
// +build js

package os

import (
	"errors"
	_ "unsafe" // for go:linkname

	"github.com/gopherjs/gopherjs/js"
)

const isBigEndian = false

func runtime_args() []string { // not called on Windows
	return Args
}

func init() {
	if process := js.Global.Get("process"); process != js.Undefined {
		if argv := process.Get("argv"); argv != js.Undefined {
			Args = make([]string, argv.Length()-1)
			for i := 0; i < argv.Length()-1; i++ {
				Args[i] = argv.Index(i + 1).String()
			}
		}
	}
	if len(Args) == 0 {
		Args = []string{"?"}
	}
}

func runtime_beforeExit() {}

func executable() (string, error) {
	return "", errors.New("Executable not implemented for GOARCH=js")
}

//go:linkname fastrand runtime.fastrand
func fastrand() uint32
<|endoftext|>


<commit_before>package core

type Command struct {
<<<<<<< HEAD
	Dockerimage string   `bson:"Dockerimage" json:"Dockerimage"`
	Name        string   `bson:"name" json:"name"`
	Options     string   `bson:"options" json:"-"`
	Args        string   `bson:"args" json:"args"`
	Template    string   `bson:"template" json:"-"`
	Description string   `bson:"description" json:"description"`
	ParsedArgs  []string `bson:"-" json:"-"`
}

func (c *Command) Substitute(inputs *IOmap, outputs *IOmap) (err error) {
	if len(c.Template) == 0 {
		return
	}
	for _, s := range TemplateRe.FindAllString(c.Template, -1) {
		print(s + "\n")
	}
	return
=======
	Name        string            `bson:"name" json:"name"`
	Args        string            `bson:"args" json:"args"`
	Dockerimage string   		   `bson:"Dockerimage" json:"Dockerimage"`
	Environ     map[string]string `bson:"environ" json:"environ"`
	Description string            `bson:"description" json:"description"`
	ParsedArgs  []string          `bson:"-" json:"-"`
>>>>>>> ce578bed8944f29dade6b9700b5cea01457b8129
}

func NewCommand(name string) *Command {
	return &Command{
		Name: name,
	}
}
<commit_msg>fixed conflicts<commit_after>package core

type Command struct {
	Name        string            `bson:"name" json:"name"`
	Args        string            `bson:"args" json:"args"`
	Dockerimage string   		   `bson:"Dockerimage" json:"Dockerimage"`
	Environ     map[string]string `bson:"environ" json:"environ"`
	Description string            `bson:"description" json:"description"`
	ParsedArgs  []string          `bson:"-" json:"-"`
}

func NewCommand(name string) *Command {
	return &Command{
		Name: name,
	}
}
<|endoftext|>


<commit_before>package lzma

import "io"

// Writer supports the LZMA compression of a file. Note that the LZMA encoder
// doesn't support flushing because of the arithmetic coding included.
type Writer struct {
	unpackLen  uint64
	writtenLen uint64
}

func NewWriter(w io.Writer, p *Properties) (*Writer, error) {
	return NewWriterLenEOS(w, p, NoUnpackLen, true)
}

func NewWriterLen(w io.Writer, p *Properties, length uint64) (*Writer, error) {
	return NewWriterLenEOS(w, p, length, false)
}

func NewWriterLenEOS(w io.Writer, p *Properties, length uint64, eos bool) (*Writer, error) {
	if length == NoUnpackLen {
		eos = true
	}
	panic("TODO")
}

// Writes data into the writer buffer.
func (l *Writer) Write(p []byte) (int, error) {
	panic("TODO")
}

// Close flushes all data out and writes the EOS marker if requested.
func (l *Writer) Close() error {
	panic("TODO")
}

/*

# Ideas

We need an encoder dictionary in which data can be written. For the encoder the
dictionary should be not be bigger than the history size. We continue to use a
ring buffer.

*/
<commit_msg>lzma: added documentation comments to writer.go<commit_after>package lzma

import "io"

// Writer supports the LZMA compression of a file. It cannot support flushing
// because of the arithmethic coder.
type Writer struct {
	unpackLen  uint64
	writtenLen uint64
}

// NewWriter creates a new LZMA writer using the given properties. It doesn't
// provide an unpack length and creates an explicit end of stream. The classic
// LZMA header will be created.
func NewWriter(w io.Writer, p *Properties) (*Writer, error) {
	return NewWriterLenEOS(w, p, NoUnpackLen, true)
}

// NewWriterLen creates a new LZMA writer and a predefined length. There will
// be no end-of-stream marker created unless NoUnpackLen is used as length.
func NewWriterLen(w io.Writer, p *Properties, length uint64) (*Writer, error) {
	return NewWriterLenEOS(w, p, length, false)
}

// NewWriterLenEOS creates a new LZMA writer. A predefinied length can be
// provided and the writing of an end-of-stream marker can be controlled. If
// the argument NoUnpackLen will be provided for the lenght a end-of-stream
// marker will be written regardless of the eos parameter.
func NewWriterLenEOS(w io.Writer, p *Properties, length uint64, eos bool) (*Writer, error) {
	if length == NoUnpackLen {
		eos = true
	}
	panic("TODO")
}

// Writes data into the writer buffer.
func (l *Writer) Write(p []byte) (int, error) {
	panic("TODO")
}

// Close flushes all data out and writes the EOS marker if requested.
func (l *Writer) Close() error {
	panic("TODO")
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"regexp"
	"runtime/debug"
	"strings"

	"github.com/shiena/ansicolor"

	"../alias"
	"../commands"
	"../completion"
	"../conio"
	"../dos"
	"../history"
	"../interpreter"
	"../lua"
)

var rxAnsiEscCode = regexp.MustCompile("\x1b[^a-zA-Z]*[a-zA-Z]")

var stamp string
var commit string
var version string
var ansiOut io.Writer

func nyagosPrompt(L lua.Lua) int {
	template, err := L.ToString(-1)
	if err != nil {
		template = "[" + err.Error() + "]"
	}
	text := Format2Prompt(template)
	fmt.Fprint(ansiOut, text)
	text = rxAnsiEscCode.ReplaceAllString(text, "")
	lfPos := strings.LastIndex(text, "\n")
	if lfPos >= 0 {
		text = text[lfPos+1:]
	}
	L.PushInteger(lua.Integer(conio.GetStringWidth(text)))
	return 1
}

var prompt_hook lua.Pushable = lua.TGoFunction{nyagosPrompt}

func printPrompt(this *conio.LineEditor) (int, error) {
	it, it_ok := this.Tag.(*interpreter.Interpreter)
	if !it_ok {
		return 0, errors.New("nyagos.go: printPrompt: conio.LineEditor.Tag is not interpreter.Interpreter")
	}
	if it.IsBackGround {
		return 0, &LuaNotRunBackGroundError{"nyagos.prompt"}
	}
	L, L_ok := it.Tag.(lua.Lua)
	if !L_ok {
		return 0, errors.New("nyagos.go: printPrompt: interpreter.Interpreter.Tag is not lua.Lua")
	}
	defer L.SetTop(L.GetTop())
	L.Push(prompt_hook)

	if !L.IsFunction(-1) {
		L.Pop(1)
		return 0, nil
	}
	L.PushString(os.Getenv("PROMPT"))
	if err := NyagosCallLua(it, 1, 1); err != nil {
		return 0, err
	}
	length, lengthErr := L.ToInteger(-1)
	L.Pop(1)
	if lengthErr == nil {
		return length, nil
	} else {
		return 0, fmt.Errorf("nyagos.prompt: return-value(length) is invalid: %s", lengthErr.Error())
	}
}

func when_panic() {
	err := recover()
	if err == nil {
		return
	}
	fmt.Fprintln(os.Stderr, "************ Panic Occured. ***********")
	fmt.Fprintln(os.Stderr, err)
	debug.PrintStack()
	fmt.Fprintln(os.Stderr, "*** Please copy these error message ***")
	fmt.Fprintln(os.Stderr, "*** And hit ENTER key to quit.      ***")
	var dummy [1]byte
	os.Stdin.Read(dummy[:])
}

var luaFilter lua.Pushable = lua.TNil{}

func main() {
	defer when_panic()

	dos.CoInitializeEx(0, dos.COINIT_MULTITHREADED)
	defer dos.CoUninitialize()

	conio.DisableCtrlC()

	completion := conio.KeyGoFuncT{F: completion.KeyFuncCompletion}

	if err := conio.BindKeySymbolFunc(conio.K_CTRL_I, "COMPLETE", &completion); err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
	}

	// ANSI Escape Sequence Support
	ansiOut = ansicolor.NewAnsiColorWriter(os.Stdout)

	commands.Init()
	alias.Init()

	// Lua extension
	L := NewNyagosLua()
	defer L.Close()

	if !optionParse(L) {
		return
	}

	appData := filepath.Join(os.Getenv("APPDATA"), "NYAOS_ORG")
	os.Mkdir(appData, 0777)
	histPath := filepath.Join(appData, "nyagos.history")
	history.Load(histPath)
	history.Save(histPath) // cut over max-line

	exeName, exeNameErr := dos.GetModuleFileName()
	if exeNameErr != nil {
		fmt.Fprintln(os.Stderr, exeNameErr)
	}
	exeFolder := filepath.Dir(exeName)
	nyagos_lua := filepath.Join(exeFolder, "nyagos.lua")
	if _, err := os.Stat(nyagos_lua); err == nil {
		err := L.Source(nyagos_lua)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
		}
	}

	conio.DefaultEditor.Prompt = printPrompt

	for {
		it := interpreter.New()
		it.Tag = L
		it.CloneHook = func(this *interpreter.Interpreter) error {
			this.Tag = NewNyagosLua()
			it.CloseHook = func(this *interpreter.Interpreter) {
				if this.Tag != nil {
					if L, ok := this.Tag.(lua.Lua); ok {
						L.Close()
					}
					this.Tag = nil
				}
			}
			return nil
		}
		conio.DefaultEditor.Tag = it

		wd, wdErr := os.Getwd()
		if wdErr == nil {
			conio.SetTitle("NYAGOS - " + wd)
		} else {
			conio.SetTitle("NYAGOS - " + wdErr.Error())
		}
		history_count := conio.DefaultEditor.HistoryLen()
		line, err := conio.DefaultEditor.ReadLine()
		if err != nil {
			fmt.Fprintln(os.Stderr, err.Error())
			break
		}

		var isReplaced bool
		line, isReplaced = history.Replace(line)
		if isReplaced {
			fmt.Fprintln(os.Stdout, line)
		}
		if line == "" {
			continue
		}
		if conio.DefaultEditor.HistoryLen() > history_count {
			fd, err := os.OpenFile(histPath, os.O_APPEND, 0600)
			if err == nil {
				fmt.Fprintln(fd, line)
				fd.Close()
			} else {
				fmt.Fprintln(os.Stderr, err.Error())
			}
		} else {
			conio.DefaultEditor.HistoryResetPointer()
		}

		stackPos := L.GetTop()
		L.Push(luaFilter)
		if L.IsFunction(-1) {
			L.PushString(line)
			err := L.Call(1, 1)
			if err != nil {
				fmt.Fprintln(os.Stderr, err)
			} else {
				if L.IsString(-1) {
					line, err = L.ToString(-1)
					if err != nil {
						fmt.Fprintln(os.Stderr, err)
					}
				}
			}
		}
		L.SetTop(stackPos)

		whatToDo, err := it.Interpret(line)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
		}
		if whatToDo == interpreter.SHUTDOWN {
			break
		}
	}
}
<commit_msg>nyagos.prompt uses it own lua-instance<commit_after>package main

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

	"github.com/shiena/ansicolor"

	"../alias"
	"../commands"
	"../completion"
	"../conio"
	"../dos"
	"../history"
	"../interpreter"
	"../lua"
)

var rxAnsiEscCode = regexp.MustCompile("\x1b[^a-zA-Z]*[a-zA-Z]")

var stamp string
var commit string
var version string
var ansiOut io.Writer

func nyagosPrompt(L lua.Lua) int {
	template, err := L.ToString(-1)
	if err != nil {
		template = "[" + err.Error() + "]"
	}
	text := Format2Prompt(template)
	fmt.Fprint(ansiOut, text)
	text = rxAnsiEscCode.ReplaceAllString(text, "")
	lfPos := strings.LastIndex(text, "\n")
	if lfPos >= 0 {
		text = text[lfPos+1:]
	}
	L.PushInteger(lua.Integer(conio.GetStringWidth(text)))
	return 1
}

var prompt_hook lua.Pushable = lua.TGoFunction{nyagosPrompt}

func printPrompt(this *conio.LineEditor) (int, error) {
	L := NewNyagosLua()
	defer L.Close()
	L.Push(prompt_hook)

	if !L.IsFunction(-1) {
		L.Pop(1)
		return 0, nil
	}
	L.PushString(os.Getenv("PROMPT"))
	if err := L.Call(1, 1); err != nil {
		return 0, err
	}
	length, lengthErr := L.ToInteger(-1)
	L.Pop(1)
	if lengthErr == nil {
		return length, nil
	} else {
		return 0, fmt.Errorf("nyagos.prompt: return-value(length) is invalid: %s", lengthErr.Error())
	}
}

func when_panic() {
	err := recover()
	if err == nil {
		return
	}
	fmt.Fprintln(os.Stderr, "************ Panic Occured. ***********")
	fmt.Fprintln(os.Stderr, err)
	debug.PrintStack()
	fmt.Fprintln(os.Stderr, "*** Please copy these error message ***")
	fmt.Fprintln(os.Stderr, "*** And hit ENTER key to quit.      ***")
	var dummy [1]byte
	os.Stdin.Read(dummy[:])
}

var luaFilter lua.Pushable = lua.TNil{}

func main() {
	defer when_panic()

	dos.CoInitializeEx(0, dos.COINIT_MULTITHREADED)
	defer dos.CoUninitialize()

	conio.DisableCtrlC()

	completion := conio.KeyGoFuncT{F: completion.KeyFuncCompletion}

	if err := conio.BindKeySymbolFunc(conio.K_CTRL_I, "COMPLETE", &completion); err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
	}

	// ANSI Escape Sequence Support
	ansiOut = ansicolor.NewAnsiColorWriter(os.Stdout)

	commands.Init()
	alias.Init()

	// Lua extension
	L := NewNyagosLua()
	defer L.Close()

	if !optionParse(L) {
		return
	}

	appData := filepath.Join(os.Getenv("APPDATA"), "NYAOS_ORG")
	os.Mkdir(appData, 0777)
	histPath := filepath.Join(appData, "nyagos.history")
	history.Load(histPath)
	history.Save(histPath) // cut over max-line

	exeName, exeNameErr := dos.GetModuleFileName()
	if exeNameErr != nil {
		fmt.Fprintln(os.Stderr, exeNameErr)
	}
	exeFolder := filepath.Dir(exeName)
	nyagos_lua := filepath.Join(exeFolder, "nyagos.lua")
	if _, err := os.Stat(nyagos_lua); err == nil {
		err := L.Source(nyagos_lua)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
		}
	}

	conio.DefaultEditor.Prompt = printPrompt

	for {
		it := interpreter.New()
		it.Tag = L
		it.CloneHook = func(this *interpreter.Interpreter) error {
			this.Tag = NewNyagosLua()
			it.CloseHook = func(this *interpreter.Interpreter) {
				if this.Tag != nil {
					if L, ok := this.Tag.(lua.Lua); ok {
						L.Close()
					}
					this.Tag = nil
				}
			}
			return nil
		}
		conio.DefaultEditor.Tag = it

		wd, wdErr := os.Getwd()
		if wdErr == nil {
			conio.SetTitle("NYAGOS - " + wd)
		} else {
			conio.SetTitle("NYAGOS - " + wdErr.Error())
		}
		history_count := conio.DefaultEditor.HistoryLen()
		line, err := conio.DefaultEditor.ReadLine()
		if err != nil {
			fmt.Fprintln(os.Stderr, err.Error())
			break
		}

		var isReplaced bool
		line, isReplaced = history.Replace(line)
		if isReplaced {
			fmt.Fprintln(os.Stdout, line)
		}
		if line == "" {
			continue
		}
		if conio.DefaultEditor.HistoryLen() > history_count {
			fd, err := os.OpenFile(histPath, os.O_APPEND, 0600)
			if err == nil {
				fmt.Fprintln(fd, line)
				fd.Close()
			} else {
				fmt.Fprintln(os.Stderr, err.Error())
			}
		} else {
			conio.DefaultEditor.HistoryResetPointer()
		}

		stackPos := L.GetTop()
		L.Push(luaFilter)
		if L.IsFunction(-1) {
			L.PushString(line)
			err := L.Call(1, 1)
			if err != nil {
				fmt.Fprintln(os.Stderr, err)
			} else {
				if L.IsString(-1) {
					line, err = L.ToString(-1)
					if err != nil {
						fmt.Fprintln(os.Stderr, err)
					}
				}
			}
		}
		L.SetTop(stackPos)

		whatToDo, err := it.Interpret(line)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
		}
		if whatToDo == interpreter.SHUTDOWN {
			break
		}
	}
}
<|endoftext|>


<commit_before>package mallory

import (
	"errors"
	"flag"
	"os"
)

const (
	CO_RED    = "\033[0;31;49m"
	CO_GREEN  = "\033[0;32;49m"
	CO_YELLOW = "\033[0;33;49m"
	CO_BLUE   = "\033[0;34;49m"
	CO_RESET  = "\033[0m"
)

// Provide global config for mallory
type Env struct {
	// work space, default is $HOME/.mallory
	Work string
	// local addr to listen and serve, default is 127.0.0.1:18087
	Addr string
	// remote engine to be used, "gae" or "direct"(default)
	Engine string
	// GAE application ID, only valid when the engine is "gae"
	// e.g. kill-me-baby of http://kill-me-baby.appspot.com
	AppSpot string
	// > http://www.akadia.com/services/ssh_test_certificate.html
	// > http://mitmproxy.org/doc/ssl.html
	// RSA private key file and self-signed root certificate file
	// Can be generated by OpenSSL:
	// - RSA private key file, without input any extra info
	//      openssl genrsa -out mallory.key 2048
	// - Self-signed root certificate file, need input some X.509 attributes
	//   such as Country Name, Comman Name etc.
	//      openssl req -new -x509 -days 365 -key mollory.key -out mallory.crt
	Key  string // mallory.key
	Cert string // mallory.crt
	// pac file path
	PAC string
	// terminal helper, test the default logger(os.Stderr) is terminal or not
	Istty bool
}

// Prepare flags and env
func (self *Env) Parse() error {
	flag.StringVar(&self.Work, "work", "$HOME/.mallory", "Work directory for mallory")
	flag.StringVar(&self.Addr, "addr", "127.0.0.1:18087", "Mallory server address, Host:Port")
	// -appsopt=debug to connect the localhost server for debug
	flag.StringVar(&self.AppSpot, "appspot", "oribe-yasuna", "GAE application ID")
	flag.StringVar(&self.Engine, "engine", "direct", `Mallory engine, "direct" or "gae"`)
	flag.StringVar(&self.Key, "key", "mallory.key", "Mallory server private key file")
	flag.StringVar(&self.Cert, "cert", "mallory.crt", "Mallory server certificate file")
	flag.StringVar(&self.PAC, "pac", "mallory.pac", "Malllory PAC service file")

	flag.Parse()

	if self.Engine != "gae" && self.Engine != "direct" {
		return errors.New(`engine should be "direct" or "gae"`)
	}

	// expand env vars for paths
	self.Work = os.ExpandEnv(self.Work)
	self.Key = os.ExpandEnv(self.Key)
	self.Cert = os.ExpandEnv(self.Cert)
	self.PAC = os.ExpandEnv(self.PAC)

	self.Istty = Isatty(os.Stderr)
	return nil
}
<commit_msg>rollback default -pac<commit_after>package mallory

import (
	"errors"
	"flag"
	"os"
)

const (
	CO_RED    = "\033[0;31;49m"
	CO_GREEN  = "\033[0;32;49m"
	CO_YELLOW = "\033[0;33;49m"
	CO_BLUE   = "\033[0;34;49m"
	CO_RESET  = "\033[0m"
)

// Provide global config for mallory
type Env struct {
	// work space, default is $HOME/.mallory
	Work string
	// local addr to listen and serve, default is 127.0.0.1:18087
	Addr string
	// remote engine to be used, "gae" or "direct"(default)
	Engine string
	// GAE application ID, only valid when the engine is "gae"
	// e.g. kill-me-baby of http://kill-me-baby.appspot.com
	AppSpot string
	// > http://www.akadia.com/services/ssh_test_certificate.html
	// > http://mitmproxy.org/doc/ssl.html
	// RSA private key file and self-signed root certificate file
	// Can be generated by OpenSSL:
	// - RSA private key file, without input any extra info
	//      openssl genrsa -out mallory.key 2048
	// - Self-signed root certificate file, need input some X.509 attributes
	//   such as Country Name, Comman Name etc.
	//      openssl req -new -x509 -days 365 -key mollory.key -out mallory.crt
	Key  string // mallory.key
	Cert string // mallory.crt
	// pac file path
	PAC string
	// terminal helper, test the default logger(os.Stderr) is terminal or not
	Istty bool
}

// Prepare flags and env
func (self *Env) Parse() error {
	flag.StringVar(&self.Work, "work", "$HOME/.mallory", "Work directory for mallory")
	flag.StringVar(&self.Addr, "addr", "127.0.0.1:18087", "Mallory server address, Host:Port")
	// -appsopt=debug to connect the localhost server for debug
	flag.StringVar(&self.AppSpot, "appspot", "oribe-yasuna", "GAE application ID")
	flag.StringVar(&self.Engine, "engine", "direct", `Mallory engine, "direct" or "gae"`)
	flag.StringVar(&self.Key, "key", "mallory.key", "Mallory server private key file")
	flag.StringVar(&self.Cert, "cert", "mallory.crt", "Mallory server certificate file")
	flag.StringVar(&self.PAC, "pac", "", "Malllory PAC service file")

	flag.Parse()

	if self.Engine != "gae" && self.Engine != "direct" {
		return errors.New(`engine should be "direct" or "gae"`)
	}

	// expand env vars for paths
	self.Work = os.ExpandEnv(self.Work)
	self.Key = os.ExpandEnv(self.Key)
	self.Cert = os.ExpandEnv(self.Cert)
	self.PAC = os.ExpandEnv(self.PAC)

	self.Istty = Isatty(os.Stderr)
	return nil
}
<|endoftext|>