<commit_before>package cmd

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

	"github.com/acarl005/stripansi"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func Test_mrCmd(t *testing.T) {
	repo := copyTestRepo(t)
	var mrID string
	t.Run("prepare", func(t *testing.T) {
		cmd := exec.Command("sh", "-c", labBinaryPath+` mr list lab-testing | grep -m1 'mr title' | cut -c2- | awk '{print $1}' | xargs `+labBinaryPath+` mr lab-testing -d`)
		cmd.Dir = repo

		b, err := cmd.CombinedOutput()
		if err != nil {
			t.Log(string(b))
			//t.Fatal(err)
		}
	})
	t.Run("create", func(t *testing.T) {
		git := exec.Command("git", "checkout", "mrtest")
		git.Dir = repo
		b, err := git.CombinedOutput()
		if err != nil {
			t.Log(string(b))
			t.Fatal(err)
		}

		cmd := exec.Command(labBinaryPath, "mr", "create", "lab-testing", "master",
			"-m", "mr title",
			"-m", "mr description",
			"-a", "lab-testing",
		)
		cmd.Dir = repo

		b, _ = cmd.CombinedOutput()
		out := string(b)
		t.Log(out)
		require.Contains(t, out, "https://gitlab.com/lab-testing/test/-/merge_requests")

		i := strings.Index(out, "/diffs\n")
		mrID = strings.TrimPrefix(out[:i], "https://gitlab.com/lab-testing/test/-/merge_requests/")
		t.Log(mrID)
	})
	t.Run("show", func(t *testing.T) {
		if mrID == "" {
			t.Skip("mrID is empty, create likely failed")
		}
		cmd := exec.Command(labBinaryPath, "mr", "show", "lab-testing", mrID)
		cmd.Dir = repo

		b, err := cmd.CombinedOutput()
		if err != nil {
			t.Log(string(b))
			t.Fatal(err)
		}

		out := string(b)
		outStripped := stripansi.Strip(out) // This is required because glamour adds a lot of ansi chars
		require.Contains(t, out, "Project: lab-testing/test\n")
		require.Contains(t, out, "Branches: mrtest->master\n")
		require.Contains(t, out, "Status: Open\n")
		require.Contains(t, out, "Assignee: lab-testing\n")
		require.Contains(t, out, fmt.Sprintf("#%s mr title", mrID))
		require.Contains(t, out, "===================================")
		require.Contains(t, outStripped, "mr description")
		require.Contains(t, out, fmt.Sprintf("WebURL: https://gitlab.com/lab-testing/test/-/merge_requests/%s", mrID))
	})
	t.Run("delete", func(t *testing.T) {
		if mrID == "" {
			t.Skip("mrID is empty, create likely failed")
		}
		cmd := exec.Command(labBinaryPath, "mr", "lab-testing", "-d", mrID)
		cmd.Dir = repo

		b, err := cmd.CombinedOutput()
		if err != nil {
			t.Log(string(b))
			t.Fatal(err)
		}
		require.Contains(t, string(b), fmt.Sprintf("Merge Request #%s closed", mrID))
	})
}

func Test_mrCmd_MR_description_and_options(t *testing.T) {
	repo := copyTestRepo(t)
	var (
		mrID      string
		commentID string
	)
	t.Run("prepare", func(t *testing.T) {
		cmd := exec.Command("sh", "-c", labBinaryPath+` mr list lab-testing | grep -m1 'Fancy Description' | cut -c2- | awk '{print $1}' | xargs `+labBinaryPath+` mr lab-testing -d`)
		cmd.Dir = repo

		b, err := cmd.CombinedOutput()
		if err != nil {
			t.Log(string(b))
			//t.Fatal(err)
		}
	})
	t.Run("create MR from file", func(t *testing.T) {
		git := exec.Command("git", "checkout", "mrtest")
		git.Dir = repo
		b, err := git.CombinedOutput()
		if err != nil {
			t.Log(string(b))
			t.Fatal(err)
		}

		err = ioutil.WriteFile(filepath.Join(repo, "hellolab.txt"), []byte("Fancy Description\n\nFancy body of text describing this merge request.\n"), 0644)
		if err != nil {
			t.Fatal(err)
		}

		cmd := exec.Command(labBinaryPath, "mr", "create", "lab-testing", "master",
			"-F", "hellolab.txt",
			"-a", "lab-testing",
		)
		cmd.Dir = repo

		b, _ = cmd.CombinedOutput()
		out := string(b)
		t.Log(out)
		require.Contains(t, out, "https://gitlab.com/lab-testing/test/-/merge_requests")

		i := strings.Index(out, "/diffs\n")
		mrID = strings.TrimPrefix(out[:i], "https://gitlab.com/lab-testing/test/-/merge_requests/")
		t.Log(mrID)

	})
	t.Run("update MR description", func(t *testing.T) {
		update := exec.Command(labBinaryPath, "mr", "edit", "lab-testing", mrID, "-m", "Updated Description", "-m", "Updated body of text describing this merge request.")
		update.Dir = repo
		b, err := update.CombinedOutput()
		if err != nil {
			t.Log(string(b))
			t.Fatal(err)
		}
		cmd := exec.Command(labBinaryPath, "mr", "show", "lab-testing", mrID)
		cmd.Dir = repo
		b, err = cmd.CombinedOutput()
		if err != nil {
			t.Log(string(b))
			t.Fatal(err)
		}
		out := string(b)
		out = stripansi.Strip(out)

		require.Contains(t, out, "Updated Description")
		require.Contains(t, out, "Updated body of text describing this merge request.")
		require.NotContains(t, out, "Fancy")
	})
	t.Run("add MR comment", func(t *testing.T) {
		addComment := exec.Command(labBinaryPath, "mr", "note", "lab-testing", mrID, "-m", "Fancy comment on this merge request.")
		addComment.Dir = repo
		b, err := addComment.CombinedOutput()
		if err != nil {
			t.Log(string(b))
			t.Fatal(err)
		}
		out := string(b)
		s := strings.Split(out, "_")
		commentID = s[2]
		s = strings.Split(commentID, "\n")
		commentID = s[0]

		t.Log("commentID =", commentID)

		url := "https://gitlab.com/lab-testing/test/merge_requests/" + mrID + "#note_" + commentID
		require.Contains(t, out, url)
	})
	t.Run("show MR with comment", func(t *testing.T) {
		showComment := exec.Command(labBinaryPath, "mr", "show", "lab-testing", mrID, "--comments")
		showComment.Dir = repo
		b, err := showComment.CombinedOutput()
		if err != nil {
			t.Log(string(b))
			t.Fatal(err)
		}
		out := string(b)
		t.Log("commentID =", commentID)
		_commentID := "#" + commentID + ": lab-testing"
		require.Contains(t, out, _commentID)
	})
	t.Run("delete", func(t *testing.T) {
		if mrID == "" {
			t.Skip("mrID is empty, create -F likely failed")
		}
		cmd := exec.Command(labBinaryPath, "mr", "lab-testing", "-d", mrID)
		cmd.Dir = repo

		b, err := cmd.CombinedOutput()
		if err != nil {
			t.Log(string(b))
			t.Fatal(err)
		}
		require.Contains(t, string(b), fmt.Sprintf("Merge Request #%s closed", mrID))
	})
}

func Test_mrCmd_noArgs(t *testing.T) {
	repo := copyTestRepo(t)
	cmd := exec.Command(labBinaryPath, "mr")
	cmd.Dir = repo

	b, err := cmd.CombinedOutput()
	if err != nil {
		t.Log(string(b))
		t.Fatal(err)
	}
	require.Contains(t, string(b), `Usage:
  lab mr [flags]
  lab mr [command]`)
}

func Test_determineSourceRemote(t *testing.T) {
	tests := []struct {
		desc     string
		branch   string
		expected string
	}{
		{
			desc:     "branch.<name>.remote",
			branch:   "mrtest",
			expected: "lab-testing",
		},
		{
			desc:     "branch.<name>.pushRemote",
			branch:   "mrtest-pushRemote",
			expected: "lab-testing",
		},
		{
			desc:     "pushDefault without pushRemote set",
			branch:   "mrtest",
			expected: "garbageurl",
		},
		{
			desc:     "pushDefault with pushRemote set",
			branch:   "mrtest-pushRemote",
			expected: "lab-testing",
		},
	}

	// The function being tested here depends on being in the test
	// directory, where 'git config --local' can retrieve the correct
	// info from
	repo := copyTestRepo(t)
	oldWd, err := os.Getwd()
	if err != nil {
		t.Log(err)
	}
	os.Chdir(repo)

	var remoteModified bool
	for _, test := range tests {
		test := test
		if strings.Contains(test.desc, "pushDefault") && !remoteModified {
			git := exec.Command("git", "config", "--local", "remote.pushDefault", "garbageurl")
			git.Dir = repo
			b, err := git.CombinedOutput()
			if err != nil {
				t.Log(string(b))
				t.Fatal(err)
			}
			remoteModified = true
		}

		t.Run(test.desc, func(t *testing.T) {
			sourceRemote := determineSourceRemote(test.branch)
			assert.Equal(t, test.expected, sourceRemote)
		})
	}
	// Remove the added option to avoid messing with other tests
	git := exec.Command("git", "config", "--local", "--unset", "remote.pushDefault")
	git.Dir = repo
	b, err := git.CombinedOutput()
	if err != nil {
		t.Log(string(b))
		t.Fatal(err)
	}
	// And move back to the workdir we were before the test
	os.Chdir(oldWd)
}
<commit_msg>mr_test: Add approve and unapprove command tests<commit_after>package cmd

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

	"github.com/acarl005/stripansi"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func Test_mrCmd(t *testing.T) {
	repo := copyTestRepo(t)
	var mrID string
	t.Run("prepare", func(t *testing.T) {
		cmd := exec.Command("sh", "-c", labBinaryPath+` mr list lab-testing | grep -m1 'mr title' | cut -c2- | awk '{print $1}' | xargs `+labBinaryPath+` mr lab-testing -d`)
		cmd.Dir = repo

		b, err := cmd.CombinedOutput()
		if err != nil {
			t.Log(string(b))
			//t.Fatal(err)
		}
	})
	t.Run("create", func(t *testing.T) {
		git := exec.Command("git", "checkout", "mrtest")
		git.Dir = repo
		b, err := git.CombinedOutput()
		if err != nil {
			t.Log(string(b))
			t.Fatal(err)
		}

		cmd := exec.Command(labBinaryPath, "mr", "create", "lab-testing", "master",
			"-m", "mr title",
			"-m", "mr description",
			"-a", "lab-testing",
		)
		cmd.Dir = repo

		b, _ = cmd.CombinedOutput()
		out := string(b)
		t.Log(out)
		require.Contains(t, out, "https://gitlab.com/lab-testing/test/-/merge_requests")

		i := strings.Index(out, "/diffs\n")
		mrID = strings.TrimPrefix(out[:i], "https://gitlab.com/lab-testing/test/-/merge_requests/")
		t.Log(mrID)
	})
	t.Run("show", func(t *testing.T) {
		if mrID == "" {
			t.Skip("mrID is empty, create likely failed")
		}
		cmd := exec.Command(labBinaryPath, "mr", "show", "lab-testing", mrID)
		cmd.Dir = repo

		b, err := cmd.CombinedOutput()
		if err != nil {
			t.Log(string(b))
			t.Fatal(err)
		}

		out := string(b)
		outStripped := stripansi.Strip(out) // This is required because glamour adds a lot of ansi chars
		require.Contains(t, out, "Project: lab-testing/test\n")
		require.Contains(t, out, "Branches: mrtest->master\n")
		require.Contains(t, out, "Status: Open\n")
		require.Contains(t, out, "Assignee: lab-testing\n")
		require.Contains(t, out, fmt.Sprintf("#%s mr title", mrID))
		require.Contains(t, out, "===================================")
		require.Contains(t, outStripped, "mr description")
		require.Contains(t, out, fmt.Sprintf("WebURL: https://gitlab.com/lab-testing/test/-/merge_requests/%s", mrID))
	})
	// Users cannot approve and unapprove their own MRs.  Comment out
	// these tests for now until a better solution can be found.
	//
	//t.Run("approve", func(t *testing.T) {
	//	if mrID == "" {
	//		t.Skip("mrID is empty, create likely failed")
	//	}
	//	cmd := exec.Command(labBinaryPath, "mr", "lab-testing", "approve", mrID)
	//	cmd.Dir = repo
	//
	//	//b, err := cmd.CombinedOutput()
	//	if err != nil {
	//		t.Log(string(b))
	//		t.Fatal(err)
	//	}
	//	require.Contains(t, string(b), fmt.Sprintf("Merge Request #%s approved", mrID))
	//})
	//t.Run("unapprove", func(t *testing.T) {
	//	if mrID == "" {
	//		t.Skip("mrID is empty, create likely failed")
	//	}
	//	cmd := exec.Command(labBinaryPath, "mr", "lab-testing", "unapprove", mrID)
	//	cmd.Dir = repo
	//
	//	b, err := cmd.CombinedOutput()
	//	if err != nil {
	//		t.Log(string(b))
	//		t.Fatal(err)
	//	}
	//	require.Contains(t, string(b), fmt.Sprintf("Merge Request #%s unapproved", mrID))
	//})
	t.Run("delete", func(t *testing.T) {
		if mrID == "" {
			t.Skip("mrID is empty, create likely failed")
		}
		cmd := exec.Command(labBinaryPath, "mr", "lab-testing", "-d", mrID)
		cmd.Dir = repo

		b, err := cmd.CombinedOutput()
		if err != nil {
			t.Log(string(b))
			t.Fatal(err)
		}
		require.Contains(t, string(b), fmt.Sprintf("Merge Request #%s closed", mrID))
	})
}

func Test_mrCmd_MR_description_and_options(t *testing.T) {
	repo := copyTestRepo(t)
	var (
		mrID      string
		commentID string
	)
	t.Run("prepare", func(t *testing.T) {
		cmd := exec.Command("sh", "-c", labBinaryPath+` mr list lab-testing | grep -m1 'Fancy Description' | cut -c2- | awk '{print $1}' | xargs `+labBinaryPath+` mr lab-testing -d`)
		cmd.Dir = repo

		b, err := cmd.CombinedOutput()
		if err != nil {
			t.Log(string(b))
			//t.Fatal(err)
		}
	})
	t.Run("create MR from file", func(t *testing.T) {
		git := exec.Command("git", "checkout", "mrtest")
		git.Dir = repo
		b, err := git.CombinedOutput()
		if err != nil {
			t.Log(string(b))
			t.Fatal(err)
		}

		err = ioutil.WriteFile(filepath.Join(repo, "hellolab.txt"), []byte("Fancy Description\n\nFancy body of text describing this merge request.\n"), 0644)
		if err != nil {
			t.Fatal(err)
		}

		cmd := exec.Command(labBinaryPath, "mr", "create", "lab-testing", "master",
			"-F", "hellolab.txt",
			"-a", "lab-testing",
		)
		cmd.Dir = repo

		b, _ = cmd.CombinedOutput()
		out := string(b)
		t.Log(out)
		require.Contains(t, out, "https://gitlab.com/lab-testing/test/-/merge_requests")

		i := strings.Index(out, "/diffs\n")
		mrID = strings.TrimPrefix(out[:i], "https://gitlab.com/lab-testing/test/-/merge_requests/")
		t.Log(mrID)

	})
	t.Run("update MR description", func(t *testing.T) {
		update := exec.Command(labBinaryPath, "mr", "edit", "lab-testing", mrID, "-m", "Updated Description", "-m", "Updated body of text describing this merge request.")
		update.Dir = repo
		b, err := update.CombinedOutput()
		if err != nil {
			t.Log(string(b))
			t.Fatal(err)
		}
		cmd := exec.Command(labBinaryPath, "mr", "show", "lab-testing", mrID)
		cmd.Dir = repo
		b, err = cmd.CombinedOutput()
		if err != nil {
			t.Log(string(b))
			t.Fatal(err)
		}
		out := string(b)
		out = stripansi.Strip(out)

		require.Contains(t, out, "Updated Description")
		require.Contains(t, out, "Updated body of text describing this merge request.")
		require.NotContains(t, out, "Fancy")
	})
	t.Run("add MR comment", func(t *testing.T) {
		addComment := exec.Command(labBinaryPath, "mr", "note", "lab-testing", mrID, "-m", "Fancy comment on this merge request.")
		addComment.Dir = repo
		b, err := addComment.CombinedOutput()
		if err != nil {
			t.Log(string(b))
			t.Fatal(err)
		}
		out := string(b)
		s := strings.Split(out, "_")
		commentID = s[2]
		s = strings.Split(commentID, "\n")
		commentID = s[0]

		t.Log("commentID =", commentID)

		url := "https://gitlab.com/lab-testing/test/merge_requests/" + mrID + "#note_" + commentID
		require.Contains(t, out, url)
	})
	t.Run("show MR with comment", func(t *testing.T) {
		showComment := exec.Command(labBinaryPath, "mr", "show", "lab-testing", mrID, "--comments")
		showComment.Dir = repo
		b, err := showComment.CombinedOutput()
		if err != nil {
			t.Log(string(b))
			t.Fatal(err)
		}
		out := string(b)
		t.Log("commentID =", commentID)
		_commentID := "#" + commentID + ": lab-testing"
		require.Contains(t, out, _commentID)
	})
	t.Run("delete", func(t *testing.T) {
		if mrID == "" {
			t.Skip("mrID is empty, create -F likely failed")
		}
		cmd := exec.Command(labBinaryPath, "mr", "lab-testing", "-d", mrID)
		cmd.Dir = repo

		b, err := cmd.CombinedOutput()
		if err != nil {
			t.Log(string(b))
			t.Fatal(err)
		}
		require.Contains(t, string(b), fmt.Sprintf("Merge Request #%s closed", mrID))
	})
}

func Test_mrCmd_noArgs(t *testing.T) {
	repo := copyTestRepo(t)
	cmd := exec.Command(labBinaryPath, "mr")
	cmd.Dir = repo

	b, err := cmd.CombinedOutput()
	if err != nil {
		t.Log(string(b))
		t.Fatal(err)
	}
	require.Contains(t, string(b), `Usage:
  lab mr [flags]
  lab mr [command]`)
}

func Test_determineSourceRemote(t *testing.T) {
	tests := []struct {
		desc     string
		branch   string
		expected string
	}{
		{
			desc:     "branch.<name>.remote",
			branch:   "mrtest",
			expected: "lab-testing",
		},
		{
			desc:     "branch.<name>.pushRemote",
			branch:   "mrtest-pushRemote",
			expected: "lab-testing",
		},
		{
			desc:     "pushDefault without pushRemote set",
			branch:   "mrtest",
			expected: "garbageurl",
		},
		{
			desc:     "pushDefault with pushRemote set",
			branch:   "mrtest-pushRemote",
			expected: "lab-testing",
		},
	}

	// The function being tested here depends on being in the test
	// directory, where 'git config --local' can retrieve the correct
	// info from
	repo := copyTestRepo(t)
	oldWd, err := os.Getwd()
	if err != nil {
		t.Log(err)
	}
	os.Chdir(repo)

	var remoteModified bool
	for _, test := range tests {
		test := test
		if strings.Contains(test.desc, "pushDefault") && !remoteModified {
			git := exec.Command("git", "config", "--local", "remote.pushDefault", "garbageurl")
			git.Dir = repo
			b, err := git.CombinedOutput()
			if err != nil {
				t.Log(string(b))
				t.Fatal(err)
			}
			remoteModified = true
		}

		t.Run(test.desc, func(t *testing.T) {
			sourceRemote := determineSourceRemote(test.branch)
			assert.Equal(t, test.expected, sourceRemote)
		})
	}
	// Remove the added option to avoid messing with other tests
	git := exec.Command("git", "config", "--local", "--unset", "remote.pushDefault")
	git.Dir = repo
	b, err := git.CombinedOutput()
	if err != nil {
		t.Log(string(b))
		t.Fatal(err)
	}
	// And move back to the workdir we were before the test
	os.Chdir(oldWd)
}
<|endoftext|>


<commit_before>package geometry

import (
	"testing"
)

func TestPointDistance2D(t *testing.T) {
	p1 := &Point2D{-2, 1}
	p2 := &Point2D{1, 5}
	if p1.DistanceTo(p2) != 5 {
		t.Error("Point2D.DistanceTo")
	}
}

func TestPointDistanceSquared2D(t *testing.T) {
	p1 := &Point2D{-2, 1}
	p2 := &Point2D{1, 5}
	if p1.SquaredDistanceTo(p2) != 25 {
		t.Error("Point2D.SquaredDistanceTo")
	}
}

func TestPoint2DCore(t *testing.T) {
	p := &Point2D{0, 0}
	p.Add(&Point2D{2, 1})
	if !p.Equal(&Point2D{2, 1}) {
		t.Error("Point2D.Add")
	}
	p.Subtract(&Point2D{1, 1})
	if !p.Equal(&Point2D{1, 0}) {
		t.Error("Point2D.Subtract")
	}
}

func TestPoint2DFuzzyEqual(t *testing.T) {
	p1 := &Point2D{1.0, 1.0}
	p2 := &Point2D{1.0, 1.0}
	if !p1.Equal(p2) {
		t.Error("Point2D.Equal")
	}
	p2.X += 0.0000000000001
	if p1.Equal(p2) {
		t.Error("Point2D.Equal")
	}
	if !p1.FuzzyEqual(p2) {
		t.Error("Point2D.FuzzyEqual")
	}
	p2.Y += 0.000000000001
	if p1.Equal(p2) {
		t.Error("Point2D.Equal")
	}
	if p1.FuzzyEqual(p2) {
		t.Error("Point2D.FuzzyEqual")
	}
}
<commit_msg>Added benchmarks for point timings.<commit_after>package geometry

import (
	"testing"
)

func TestPoint2DCore(t *testing.T) {
	p := &Point2D{0, 0}
	p.Add(&Point2D{2, 1})
	if !p.Equal(&Point2D{2, 1}) {
		t.Error("Point2D.Add")
	}
	p.Subtract(&Point2D{1, 1})
	if !p.Equal(&Point2D{1, 0}) {
		t.Error("Point2D.Subtract")
	}
}

func Benchmark_Point2D_Add(b *testing.B) {
	p1, p2 := &Point2D{1, 1}, &Point2D{2, 1}
	for i := 0; i < b.N; i++ {
		p1.Add(p2)
	}
}

func Benchmark_Point2D_Subtract(b *testing.B) {
	p1, p2 := &Point2D{1, 1}, &Point2D{2, 1}
	for i := 0; i < b.N; i++ {
		p1.Subtract(p2)
	}
}

func TestPointDistance2D(t *testing.T) {
	p1 := &Point2D{-2, 1}
	p2 := &Point2D{1, 5}
	if p1.DistanceTo(p2) != 5 {
		t.Error("Point2D.DistanceTo")
	}
}

func Benchmark_Point2D_Distance(b *testing.B) {
	p1, p2 := &Point2D{1, 1}, &Point2D{2, 1}
	for i := 0; i < b.N; i++ {
		p1.DistanceTo(p2)
	}
}

func TestPointDistanceSquared2D(t *testing.T) {
	p1 := &Point2D{-2, 1}
	p2 := &Point2D{1, 5}
	if p1.SquaredDistanceTo(p2) != 25 {
		t.Error("Point2D.SquaredDistanceTo")
	}
}

func Benchmark_Point2D_SquaredDistance(b *testing.B) {
	p1, p2 := &Point2D{1, 1}, &Point2D{2, 1}
	for i := 0; i < b.N; i++ {
		p1.SquaredDistanceTo(p2)
	}
}

func TestPoint2DFuzzyEqual(t *testing.T) {
	p1 := &Point2D{1.0, 1.0}
	p2 := &Point2D{1.0, 1.0}
	if !p1.Equal(p2) {
		t.Error("Point2D.Equal")
	}
	p2.X += 0.0000000000001
	if p1.Equal(p2) {
		t.Error("Point2D.Equal")
	}
	if !p1.FuzzyEqual(p2) {
		t.Error("Point2D.FuzzyEqual")
	}
	p2.Y += 0.000000000001
	if p1.Equal(p2) {
		t.Error("Point2D.Equal")
	}
	if p1.FuzzyEqual(p2) {
		t.Error("Point2D.FuzzyEqual")
	}
}

func Benchmark_Point2D_Equal_1(b *testing.B) {
	p1, p2 := &Point2D{1, 1}, &Point2D{2, 1}
	for i := 0; i < b.N; i++ {
		p1.Equal(p2)
	}
}

func Benchmark_Point2D_Equal_2(b *testing.B) {
	p1, p2 := &Point2D{1, 1}, &Point2D{1, 1}
	for i := 0; i < b.N; i++ {
		p1.Equal(p2)
	}
}

func Benchmark_Point2D_FuzzyEqual(b *testing.B) {
	p1, p2 := &Point2D{1, 1}, &Point2D{2, 1}
	for i := 0; i < b.N; i++ {
		p1.FuzzyEqual(p2)
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright 2021 The Knative 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 v2

import (
	"context"

	"k8s.io/client-go/tools/cache"
	consumergroupclient "knative.dev/eventing-kafka-broker/control-plane/pkg/client/internals/kafka/injection/client"
	consumergroupinformer "knative.dev/eventing-kafka-broker/control-plane/pkg/client/internals/kafka/injection/informers/eventing/v1alpha1/consumergroup"
	"knative.dev/pkg/controller"

	sources "knative.dev/eventing-kafka/pkg/apis/sources/v1beta1"

	kafkainformer "knative.dev/eventing-kafka/pkg/client/injection/informers/sources/v1beta1/kafkasource"
	"knative.dev/eventing-kafka/pkg/client/injection/reconciler/sources/v1beta1/kafkasource"

	"knative.dev/eventing-kafka-broker/control-plane/pkg/config"
	"knative.dev/eventing-kafka-broker/control-plane/pkg/reconciler/consumergroup"
)

func NewController(ctx context.Context, configs *config.Env) *controller.Impl {

	kafkaInformer := kafkainformer.Get(ctx)
	consumerGroupInformer := consumergroupinformer.Get(ctx)

	sources.RegisterAlternateKafkaConditionSet(conditionSet)

	r := &Reconciler{
		ConsumerGroupLister: consumerGroupInformer.Lister(),
		InternalsClient:     consumergroupclient.Get(ctx),
	}

	impl := kafkasource.NewImpl(ctx, r)

	kafkaInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{
		Handler: controller.HandleAll(impl.Enqueue),
	})

	// ConsumerGroup changes and enqueue associated KafkaSource
	consumerGroupInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{
		FilterFunc: consumergroup.Filter("kafkasource"),
		Handler:    controller.HandleAll(consumergroup.Enqueue("kafkasource", impl.EnqueueKey)),
	})
	return impl
}
<commit_msg>Fix KafkaSource v2 controller handlers (#1852)<commit_after>/*
 * Copyright 2021 The Knative 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 v2

import (
	"context"

	"k8s.io/client-go/tools/cache"
	"knative.dev/pkg/controller"

	consumergroupclient "knative.dev/eventing-kafka-broker/control-plane/pkg/client/internals/kafka/injection/client"
	consumergroupinformer "knative.dev/eventing-kafka-broker/control-plane/pkg/client/internals/kafka/injection/informers/eventing/v1alpha1/consumergroup"

	sources "knative.dev/eventing-kafka/pkg/apis/sources/v1beta1"

	kafkainformer "knative.dev/eventing-kafka/pkg/client/injection/informers/sources/v1beta1/kafkasource"
	"knative.dev/eventing-kafka/pkg/client/injection/reconciler/sources/v1beta1/kafkasource"

	"knative.dev/eventing-kafka-broker/control-plane/pkg/config"
	"knative.dev/eventing-kafka-broker/control-plane/pkg/reconciler/consumergroup"
)

func NewController(ctx context.Context, configs *config.Env) *controller.Impl {

	kafkaInformer := kafkainformer.Get(ctx)
	consumerGroupInformer := consumergroupinformer.Get(ctx)

	sources.RegisterAlternateKafkaConditionSet(conditionSet)

	r := &Reconciler{
		ConsumerGroupLister: consumerGroupInformer.Lister(),
		InternalsClient:     consumergroupclient.Get(ctx),
	}

	impl := kafkasource.NewImpl(ctx, r)

	kafkaInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue))

	// ConsumerGroup changes and enqueue associated KafkaSource
	consumerGroupInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{
		FilterFunc: consumergroup.Filter("kafkasource"),
		Handler:    controller.HandleAll(consumergroup.Enqueue("kafkasource", impl.EnqueueKey)),
	})
	return impl
}
<|endoftext|>


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

package gl

// #include "gl.h"
import "C"
import "unsafe"

// Buffer Objects

type Buffer Object

// Create single buffer object
func GenBuffer() Buffer {
	var b C.GLuint
	C.glGenBuffers(1, &b)
	return Buffer(b)
}

// Fill slice with new buffers
func GenBuffers(buffers []Buffer) {
	if len(buffers) > 0 {
		C.glGenBuffers(C.GLsizei(len(buffers)), (*C.GLuint)(&buffers[0]))
	}
}

// Delete buffer object
func (buffer Buffer) Delete() {
	b := C.GLuint(buffer)
	C.glDeleteBuffers(1, &b)
}

// Delete all buffers in slice
func DeleteBuffers(buffers []Buffer) {
	if len(buffers) > 0 {
		C.glDeleteBuffers(C.GLsizei(len(buffers)), (*C.GLuint)(&buffers[0]))
	}
}

// Bind this buffer as target
func (buffer Buffer) Bind(target GLenum) {
	C.glBindBuffer(C.GLenum(target), C.GLuint(buffer))
}

// Remove buffer binding
func (buffer Buffer) Unbind(target GLenum) {
	C.glBindBuffer(C.GLenum(target), C.GLuint(0))
}

// Bind this buffer as index of target
func (buffer Buffer) BindBufferBase(target GLenum, index uint) {
	C.glBindBufferBase(C.GLenum(target), C.GLuint(index), C.GLuint(buffer))
}

// Bind this buffer range as index of target
func (buffer Buffer) BindBufferRange(target GLenum, index uint, offset int, size uint) {
	C.glBindBufferRange(C.GLenum(target), C.GLuint(index), C.GLuint(buffer), C.GLintptr(offset), C.GLsizeiptr(size))
}

// Creates and initializes a buffer object's data store
func BufferData(target GLenum, size int, data interface{}, usage GLenum) {
	C.glBufferData(C.GLenum(target), C.GLsizeiptr(size), ptr(data), C.GLenum(usage))
}

//  Update a subset of a buffer object's data store
func BufferSubData(target GLenum, offset int, size int, data interface{}) {
	C.glBufferSubData(C.GLenum(target), C.GLintptr(offset), C.GLsizeiptr(size),
		ptr(data))
}

// Returns a subset of a buffer object's data store
func GetBufferSubData(target GLenum, offset int, size int, data interface{}) {
	C.glGetBufferSubData(C.GLenum(target), C.GLintptr(offset),
		C.GLsizeiptr(size), ptr(data))
}

//  Map a buffer object's data store
func MapBuffer(target GLenum, access GLenum) unsafe.Pointer {
	return unsafe.Pointer(C.glMapBuffer(C.GLenum(target), C.GLenum(access)))
}

//  Unmap a buffer object's data store
func UnmapBuffer(target GLenum) bool {
	return goBool(C.glUnmapBuffer(C.GLenum(target)))
}

// Return buffer pointer
func GetBufferPointerv(target GLenum, pname GLenum) unsafe.Pointer {
	var ptr unsafe.Pointer
	C.glGetBufferPointerv(C.GLenum(target), C.GLenum(pname), &ptr)
	return ptr
}

// Return parameters of a buffer object
func GetBufferParameteriv(target GLenum, pname GLenum) int32 {
	var param C.GLint
	C.glGetBufferParameteriv(C.GLenum(target), C.GLenum(pname), &param)
	return int32(param)
}
<commit_msg>Added MapBuffer convenience functions for slices<commit_after>// Copyright 2012 The go-gl Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gl

// #include "gl.h"
import "C"
import "unsafe"
import "reflect"

// Buffer Objects

type Buffer Object

// Create single buffer object
func GenBuffer() Buffer {
	var b C.GLuint
	C.glGenBuffers(1, &b)
	return Buffer(b)
}

// Fill slice with new buffers
func GenBuffers(buffers []Buffer) {
	if len(buffers) > 0 {
		C.glGenBuffers(C.GLsizei(len(buffers)), (*C.GLuint)(&buffers[0]))
	}
}

// Delete buffer object
func (buffer Buffer) Delete() {
	b := C.GLuint(buffer)
	C.glDeleteBuffers(1, &b)
}

// Delete all buffers in slice
func DeleteBuffers(buffers []Buffer) {
	if len(buffers) > 0 {
		C.glDeleteBuffers(C.GLsizei(len(buffers)), (*C.GLuint)(&buffers[0]))
	}
}

// Bind this buffer as target
func (buffer Buffer) Bind(target GLenum) {
	C.glBindBuffer(C.GLenum(target), C.GLuint(buffer))
}

// Remove buffer binding
func (buffer Buffer) Unbind(target GLenum) {
	C.glBindBuffer(C.GLenum(target), C.GLuint(0))
}

// Bind this buffer as index of target
func (buffer Buffer) BindBufferBase(target GLenum, index uint) {
	C.glBindBufferBase(C.GLenum(target), C.GLuint(index), C.GLuint(buffer))
}

// Bind this buffer range as index of target
func (buffer Buffer) BindBufferRange(target GLenum, index uint, offset int, size uint) {
	C.glBindBufferRange(C.GLenum(target), C.GLuint(index), C.GLuint(buffer), C.GLintptr(offset), C.GLsizeiptr(size))
}

// Creates and initializes a buffer object's data store
func BufferData(target GLenum, size int, data interface{}, usage GLenum) {
	C.glBufferData(C.GLenum(target), C.GLsizeiptr(size), ptr(data), C.GLenum(usage))
}

//  Update a subset of a buffer object's data store
func BufferSubData(target GLenum, offset int, size int, data interface{}) {
	C.glBufferSubData(C.GLenum(target), C.GLintptr(offset), C.GLsizeiptr(size),
		ptr(data))
}

// Returns a subset of a buffer object's data store
func GetBufferSubData(target GLenum, offset int, size int, data interface{}) {
	C.glGetBufferSubData(C.GLenum(target), C.GLintptr(offset),
		C.GLsizeiptr(size), ptr(data))
}

//  Map a buffer object's data store
func MapBuffer(target GLenum, access GLenum) unsafe.Pointer {
	return unsafe.Pointer(C.glMapBuffer(C.GLenum(target), C.GLenum(access)))
}

// Maps the buffer with MapBuffer() and returns a pointer to the slice pointing
// to the mapped buffer. See also the MapBuffer<Type> convenience functions.
func MapBufferSlice(target GLenum, access GLenum, bytesPerElement int) unsafe.Pointer {
	rawLength := int(GetBufferParameteriv(target, BUFFER_SIZE))
	return unsafe.Pointer(&reflect.SliceHeader{
		Data: uintptr(MapBuffer(target, access)),
		Len:  rawLength / bytesPerElement,
		Cap:  rawLength / bytesPerElement,
	})
}

//  Map a buffer object's data store and return it as a slice
func MapBufferFloat32(target GLenum, access GLenum) []float32 {
	return *(*[]float32)(MapBufferSlice(target, access, 4))
}

//  Map a buffer object's data store and return it as a slice
func MapBufferUint32(target GLenum, access GLenum) []uint32 {
	return *(*[]uint32)(MapBufferSlice(target, access, 4))
}

//  Unmap a buffer object's data store
func UnmapBuffer(target GLenum) bool {
	return goBool(C.glUnmapBuffer(C.GLenum(target)))
}

// Return buffer pointer
func GetBufferPointerv(target GLenum, pname GLenum) unsafe.Pointer {
	var ptr unsafe.Pointer
	C.glGetBufferPointerv(C.GLenum(target), C.GLenum(pname), &ptr)
	return ptr
}

// Return parameters of a buffer object
func GetBufferParameteriv(target GLenum, pname GLenum) int32 {
	var param C.GLint
	C.glGetBufferParameteriv(C.GLenum(target), C.GLenum(pname), &param)
	return int32(param)
}
<|endoftext|>


<commit_before>package immortal

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"os/user"
	"path/filepath"
	"strings"
	"sync/atomic"
	"testing"
	"time"
)

func TestDaemonNewCtrl(t *testing.T) {
	dir, err := ioutil.TempDir("", "TestDaemonNewCtrl")
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(dir)
	cfg := &Config{
		Cwd:  dir,
		ctrl: true,
	}
	d, err := New(cfg)
	if err != nil {
		t.Error(err)
	}
	f, err := os.Stat(filepath.Join(dir, "supervise/control"))
	if f.Mode()&os.ModeType != os.ModeNamedPipe {
		t.Error("Expecting os.ModeNamePipe")
	}
	f, err = os.Stat(filepath.Join(dir, "supervise/ok"))
	if f.Mode()&os.ModeType != os.ModeNamedPipe {
		t.Error("Expecting os.ModeNamePipe")
	}
	if _, err = os.Stat(filepath.Join(dir, "supervise/lock")); err != nil {
		t.Error(err)
	}
	expect(t, uint32(0), d.lock)
	expect(t, uint32(0), d.lock_once)
	// test lock
	_, err = New(cfg)
	if err == nil {
		t.Error("Expecting error: resource temporarily unavailable")
	}
}

func TestDaemonNewCtrlErr(t *testing.T) {
	dir, err := ioutil.TempDir("", "TestDaemonNewCtrlErr")
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(dir)
	os.Chmod(dir, 0000)
	cfg := &Config{
		Cwd:  dir,
		ctrl: true,
	}
	_, err = New(cfg)
	if err == nil {
		t.Error("Expecting error")
	}
}

func TestDaemonNewCtrlCwd(t *testing.T) {
	dir, err := ioutil.TempDir("", "TestDaemonNewCtrlCwd")
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(dir)
	cwd, err := os.Getwd()
	if err != nil {
		t.Error(err)
	}
	defer os.Chdir(cwd)
	if err := os.Chdir(dir); err != nil {
		t.Error(err)
	}
	cfg := &Config{
		ctrl: true,
	}
	d, err := New(cfg)
	if err != nil {
		t.Error(err)
	}
	f, err := os.Stat(filepath.Join(dir, "supervise/control"))
	if f.Mode()&os.ModeType != os.ModeNamedPipe {
		t.Error("Expecting os.ModeNamePipe")
	}
	f, err = os.Stat(filepath.Join(dir, "supervise/ok"))
	if f.Mode()&os.ModeType != os.ModeNamedPipe {
		t.Error("Expecting os.ModeNamePipe")
	}
	if _, err = os.Stat(filepath.Join(dir, "supervise/lock")); err != nil {
		t.Error(err)
	}
	expect(t, uint32(0), d.lock)
	expect(t, uint32(0), d.lock_once)
	// test lock
	_, err = New(cfg)
	if err == nil {
		t.Error("Expecting error: resource temporarily unavailable")
	}
}

func TestBadUid(t *testing.T) {
	cfg := &Config{
		command: []string{"--"},
		user:    &user.User{Uid: "uid", Gid: "0"},
	}
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}
	_, err = d.Run(NewProcess(cfg))
	if err == nil {
		t.Error("Expecting error")
	}
}

func TestBadGid(t *testing.T) {
	cfg := &Config{
		command: []string{"--"},
		user:    &user.User{Uid: "0", Gid: "gid"},
	}
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}
	_, err = d.Run(NewProcess(cfg))
	if err == nil {
		t.Error("Expecting error")
	}
}

func TestUser(t *testing.T) {
	cfg := &Config{
		command: []string{"go"},
		user:    &user.User{Uid: "0", Gid: "0"},
	}
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}
	_, err = d.Run(NewProcess(cfg))
	if err == nil {
		t.Error("Expecting error")
	}
}

func TestBadWritePidParent(t *testing.T) {
	var mylog bytes.Buffer
	log.SetOutput(&mylog)
	log.SetFlags(0)
	cfg := &Config{
		command: []string{"go"},
		Pid: Pid{
			Parent: "/dev/null/parent.pid",
		},
	}
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}
	_, err = d.Run(NewProcess(cfg))
	if err != nil {
		t.Fatal(err)
	}
	expect(t, "open /dev/null/parent.pid: not a directory", strings.TrimSpace(mylog.String()))
}

func TestBadWritePidChild(t *testing.T) {
	var mylog bytes.Buffer
	log.SetOutput(&mylog)
	log.SetFlags(0)
	cfg := &Config{
		command: []string{"go"},
		Pid: Pid{
			Child: "/dev/null/child.pid",
		},
	}
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}
	_, err = d.Run(NewProcess(cfg))
	if err != nil {
		t.Fatal(err)
	}
	expect(t, "open /dev/null/child.pid: not a directory", strings.TrimSpace(mylog.String()))
}

func TestHelperProcessSignalsUDOT(*testing.T) {
	if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
		return
	}
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	select {
	case <-c:
		os.Exit(1)
	case <-time.After(10 * time.Second):
		os.Exit(0)
	default:
		fmt.Println("5D675098-45D7-4089-A72C-3628713EA5BA")
	}
}

func TestSignalsUDOT(t *testing.T) {
	base := filepath.Base(os.Args[0]) // "exec.test"
	dir := filepath.Dir(os.Args[0])   // "/tmp/go-buildNNNN/os/exec/_test"
	if dir == "." {
		t.Skip("skipping; running test at root somehow")
	}
	parentDir := filepath.Dir(dir) // "/tmp/go-buildNNNN/os/exec"
	dirBase := filepath.Base(dir)  // "_test"
	if dirBase == "." {
		t.Skipf("skipping; unexpected shallow dir of %q", dir)
	}
	tmpfile, err := ioutil.TempFile("", "TestLogFile")
	if err != nil {
		t.Error(err)
	}
	defer os.Remove(tmpfile.Name()) // clean up
	cfg := &Config{
		Env:     map[string]string{"GO_WANT_HELPER_PROCESS": "1"},
		command: []string{filepath.Join(dirBase, base), "-test.run=TestHelperProcessSignalsUDOT", "--"},
		Cwd:     parentDir,
		Pid: Pid{
			Parent: filepath.Join(parentDir, "parent.pid"),
			Child:  filepath.Join(parentDir, "child.pid"),
		},
		Log: Log{
			File: tmpfile.Name(),
		},
	}
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}

	np := NewProcess(cfg)
	expect(t, 0, np.Pid())
	p, err := d.Run(np)
	if err != nil {
		t.Error(err)
	}

	sup := &Sup{p}

	// check pids
	if pid, err := sup.ReadPidFile(filepath.Join(parentDir, "parent.pid")); err != nil {
		t.Error(err)
	} else {
		expect(t, os.Getpid(), pid)
	}
	if pid, err := sup.ReadPidFile(filepath.Join(parentDir, "child.pid")); err != nil {
		t.Error(err, pid)
	} else {
		expect(t, p.Pid(), pid)
	}

	// test "k", process should restart and get a new pid
	t.Log("testing k")
	current_pid := p.Pid()
	sup.HandleSignals("k", d)
	// wait for process to finish
	err = <-p.errch
	atomic.StoreUint32(&d.lock, d.lock_once)
	expect(t, "signal: killed", err.Error())
	p, err = d.Run(NewProcess(cfg))
	if err != nil {
		t.Error(err)
	}
	sup = &Sup{p}
	if current_pid == p.Pid() {
		t.Fatalf("Expecting a new pid")
	}

	// test "d", (keep it down and don't restart)
	t.Log("testing d")
	sup.HandleSignals("d", d)
	// wait for process to finish
	err = <-p.errch
	atomic.StoreUint32(&d.lock, d.lock_once)
	if "signal: terminated" != err.Error() {
		t.Error("Expecting an error")
	}
	np = NewProcess(cfg)
	p, err = d.Run(np)
	if err == nil {
		t.Error("Expecting an error")
	} else {
		close(np.quit)
	}

	// test "u"
	t.Log("testing up")
	sup.HandleSignals("u", d)
	p, err = d.Run(NewProcess(cfg))
	if err != nil {
		t.Error(err)
	}
	sup = &Sup{p}

	// test "once", process should not restart after going down
	t.Log("testing once")
	sup.HandleSignals("o", d)
	sup.HandleSignals("k", d)
	// wait for process to finish
	err = <-p.errch
	atomic.StoreUint32(&d.lock, d.lock_once)
	expect(t, "signal: killed", err.Error())
	np = NewProcess(cfg)
	p, err = d.Run(np)
	if err == nil {
		t.Error("Expecting an error")
	} else {
		close(np.quit)
	}
	sup = &Sup{p}

	// test "u"
	t.Log("testing u")
	sup.HandleSignals("u", d)
	p, err = d.Run(NewProcess(cfg))
	if err != nil {
		t.Error(err)
	}
	sup = &Sup{p}
	old_pid := p.Pid()

	// test "t"
	t.Log("testing t")
	sup.HandleSignals("t", d)
	err = <-p.errch
	atomic.StoreUint32(&d.lock, d.lock_once)
	expect(t, "signal: terminated", err.Error())
	// restart to get new pid
	p, err = d.Run(NewProcess(cfg))
	if err != nil {
		t.Error(err)
	}
	sup = &Sup{p}
	if old_pid == p.Pid() {
		t.Fatal("Expecting a new pid")
	}

	time.Sleep(time.Second)

	sup.HandleSignals("kill", d)
	err = <-p.errch
	atomic.StoreUint32(&d.lock, d.lock_once)

	// test log content
	t.Log("testing logfile")
	content, err := ioutil.ReadFile(tmpfile.Name())
	if err != nil {
		t.Fatal(err)
	}
	lines := strings.Split(string(content), "\n")
	expect(t, true, strings.HasSuffix(lines[0], "5D675098-45D7-4089-A72C-3628713EA5BA"))
}
<commit_msg>replacing expect<commit_after>package immortal

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"os/user"
	"path/filepath"
	"strings"
	"sync/atomic"
	"testing"
	"time"
)

func TestDaemonNewCtrl(t *testing.T) {
	dir, err := ioutil.TempDir("", "TestDaemonNewCtrl")
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(dir)
	cfg := &Config{
		Cwd:  dir,
		ctrl: true,
	}
	d, err := New(cfg)
	if err != nil {
		t.Error(err)
	}
	f, err := os.Stat(filepath.Join(dir, "supervise/control"))
	if f.Mode()&os.ModeType != os.ModeNamedPipe {
		t.Error("Expecting os.ModeNamePipe")
	}
	f, err = os.Stat(filepath.Join(dir, "supervise/ok"))
	if f.Mode()&os.ModeType != os.ModeNamedPipe {
		t.Error("Expecting os.ModeNamePipe")
	}
	if _, err = os.Stat(filepath.Join(dir, "supervise/lock")); err != nil {
		t.Error(err)
	}
	expect(t, uint32(0), d.lock)
	expect(t, uint32(0), d.lock_once)
	// test lock
	_, err = New(cfg)
	if err == nil {
		t.Error("Expecting error: resource temporarily unavailable")
	}
}

func TestDaemonNewCtrlErr(t *testing.T) {
	dir, err := ioutil.TempDir("", "TestDaemonNewCtrlErr")
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(dir)
	os.Chmod(dir, 0000)
	cfg := &Config{
		Cwd:  dir,
		ctrl: true,
	}
	_, err = New(cfg)
	if err == nil {
		t.Error("Expecting error")
	}
}

func TestDaemonNewCtrlCwd(t *testing.T) {
	dir, err := ioutil.TempDir("", "TestDaemonNewCtrlCwd")
	if err != nil {
		t.Error(err)
	}
	defer os.RemoveAll(dir)
	cwd, err := os.Getwd()
	if err != nil {
		t.Error(err)
	}
	defer os.Chdir(cwd)
	if err := os.Chdir(dir); err != nil {
		t.Error(err)
	}
	cfg := &Config{
		ctrl: true,
	}
	d, err := New(cfg)
	if err != nil {
		t.Error(err)
	}
	f, err := os.Stat(filepath.Join(dir, "supervise/control"))
	if f.Mode()&os.ModeType != os.ModeNamedPipe {
		t.Error("Expecting os.ModeNamePipe")
	}
	f, err = os.Stat(filepath.Join(dir, "supervise/ok"))
	if f.Mode()&os.ModeType != os.ModeNamedPipe {
		t.Error("Expecting os.ModeNamePipe")
	}
	if _, err = os.Stat(filepath.Join(dir, "supervise/lock")); err != nil {
		t.Error(err)
	}
	expect(t, uint32(0), d.lock)
	expect(t, uint32(0), d.lock_once)
	// test lock
	_, err = New(cfg)
	if err == nil {
		t.Error("Expecting error: resource temporarily unavailable")
	}
}

func TestBadUid(t *testing.T) {
	cfg := &Config{
		command: []string{"--"},
		user:    &user.User{Uid: "uid", Gid: "0"},
	}
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}
	_, err = d.Run(NewProcess(cfg))
	if err == nil {
		t.Error("Expecting error")
	}
}

func TestBadGid(t *testing.T) {
	cfg := &Config{
		command: []string{"--"},
		user:    &user.User{Uid: "0", Gid: "gid"},
	}
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}
	_, err = d.Run(NewProcess(cfg))
	if err == nil {
		t.Error("Expecting error")
	}
}

func TestUser(t *testing.T) {
	cfg := &Config{
		command: []string{"go"},
		user:    &user.User{Uid: "0", Gid: "0"},
	}
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}
	_, err = d.Run(NewProcess(cfg))
	if err == nil {
		t.Error("Expecting error")
	}
}

func TestBadWritePidParent(t *testing.T) {
	var mylog bytes.Buffer
	log.SetOutput(&mylog)
	log.SetFlags(0)
	cfg := &Config{
		command: []string{"go"},
		Pid: Pid{
			Parent: "/dev/null/parent.pid",
		},
	}
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}
	_, err = d.Run(NewProcess(cfg))
	if err != nil {
		t.Fatal(err)
	}
	expect(t, "open /dev/null/parent.pid: not a directory", strings.TrimSpace(mylog.String()))
}

func TestBadWritePidChild(t *testing.T) {
	var mylog bytes.Buffer
	log.SetOutput(&mylog)
	log.SetFlags(0)
	cfg := &Config{
		command: []string{"go"},
		Pid: Pid{
			Child: "/dev/null/child.pid",
		},
	}
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}
	_, err = d.Run(NewProcess(cfg))
	if err != nil {
		t.Fatal(err)
	}
	expect(t, "open /dev/null/child.pid: not a directory", strings.TrimSpace(mylog.String()))
}

func TestHelperProcessSignalsUDOT(*testing.T) {
	if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
		return
	}
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	select {
	case <-c:
		os.Exit(1)
	case <-time.After(10 * time.Second):
		os.Exit(0)
	default:
		fmt.Println("5D675098-45D7-4089-A72C-3628713EA5BA")
	}
}

func TestSignalsUDOT(t *testing.T) {
	base := filepath.Base(os.Args[0]) // "exec.test"
	dir := filepath.Dir(os.Args[0])   // "/tmp/go-buildNNNN/os/exec/_test"
	if dir == "." {
		t.Skip("skipping; running test at root somehow")
	}
	parentDir := filepath.Dir(dir) // "/tmp/go-buildNNNN/os/exec"
	dirBase := filepath.Base(dir)  // "_test"
	if dirBase == "." {
		t.Skipf("skipping; unexpected shallow dir of %q", dir)
	}
	tmpfile, err := ioutil.TempFile("", "TestLogFile")
	if err != nil {
		t.Error(err)
	}
	defer os.Remove(tmpfile.Name()) // clean up
	cfg := &Config{
		Env:     map[string]string{"GO_WANT_HELPER_PROCESS": "1"},
		command: []string{filepath.Join(dirBase, base), "-test.run=TestHelperProcessSignalsUDOT", "--"},
		Cwd:     parentDir,
		Pid: Pid{
			Parent: filepath.Join(parentDir, "parent.pid"),
			Child:  filepath.Join(parentDir, "child.pid"),
		},
		Log: Log{
			File: tmpfile.Name(),
		},
	}
	d, err := New(cfg)
	if err != nil {
		t.Fatal(err)
	}

	np := NewProcess(cfg)
	expect(t, 0, np.Pid())
	p, err := d.Run(np)
	if err != nil {
		t.Error(err)
	}

	sup := &Sup{p}

	// check pids
	if pid, err := sup.ReadPidFile(filepath.Join(parentDir, "parent.pid")); err != nil {
		t.Error(err)
	} else {
		expect(t, os.Getpid(), pid)
	}
	if pid, err := sup.ReadPidFile(filepath.Join(parentDir, "child.pid")); err != nil {
		t.Error(err, pid)
	} else {
		expect(t, p.Pid(), pid)
	}

	// test "k", process should restart and get a new pid
	t.Log("testing k")
	current_pid := p.Pid()
	sup.HandleSignals("k", d)
	// wait for process to finish
	err = <-p.errch
	atomic.StoreUint32(&d.lock, d.lock_once)
	if "signal: killed" != err.Error() {
		t.Error("Expecting an error")
	}
	p, err = d.Run(NewProcess(cfg))
	if err != nil {
		t.Error(err)
	}
	sup = &Sup{p}
	if current_pid == p.Pid() {
		t.Fatalf("Expecting a new pid")
	}

	// test "d", (keep it down and don't restart)
	t.Log("testing d")
	sup.HandleSignals("d", d)
	// wait for process to finish
	err = <-p.errch
	atomic.StoreUint32(&d.lock, d.lock_once)
	if "signal: terminated" != err.Error() {
		t.Error("Expecting an error")
	}
	np = NewProcess(cfg)
	p, err = d.Run(np)
	if err == nil {
		t.Error("Expecting an error")
	} else {
		close(np.quit)
	}

	// test "u"
	t.Log("testing up")
	sup.HandleSignals("u", d)
	p, err = d.Run(NewProcess(cfg))
	if err != nil {
		t.Error(err)
	}
	sup = &Sup{p}

	// test "once", process should not restart after going down
	t.Log("testing once")
	sup.HandleSignals("o", d)
	sup.HandleSignals("k", d)
	// wait for process to finish
	err = <-p.errch
	atomic.StoreUint32(&d.lock, d.lock_once)
	expect(t, "signal: killed", err.Error())
	np = NewProcess(cfg)
	p, err = d.Run(np)
	if err == nil {
		t.Error("Expecting an error")
	} else {
		close(np.quit)
	}
	sup = &Sup{p}

	// test "u"
	t.Log("testing u")
	sup.HandleSignals("u", d)
	p, err = d.Run(NewProcess(cfg))
	if err != nil {
		t.Error(err)
	}
	sup = &Sup{p}
	old_pid := p.Pid()

	// test "t"
	t.Log("testing t")
	sup.HandleSignals("t", d)
	err = <-p.errch
	atomic.StoreUint32(&d.lock, d.lock_once)
	expect(t, "signal: terminated", err.Error())
	// restart to get new pid
	p, err = d.Run(NewProcess(cfg))
	if err != nil {
		t.Error(err)
	}
	sup = &Sup{p}
	if old_pid == p.Pid() {
		t.Fatal("Expecting a new pid")
	}

	time.Sleep(time.Second)

	sup.HandleSignals("kill", d)
	err = <-p.errch
	atomic.StoreUint32(&d.lock, d.lock_once)

	// test log content
	t.Log("testing logfile")
	content, err := ioutil.ReadFile(tmpfile.Name())
	if err != nil {
		t.Fatal(err)
	}
	lines := strings.Split(string(content), "\n")
	expect(t, true, strings.HasSuffix(lines[0], "5D675098-45D7-4089-A72C-3628713EA5BA"))
}
<|endoftext|>


<commit_before>package dao

//import (
//	"bytes"
//	"encoding/json"
//	"github.com/zenoss/glog"
//	"text/template"
//)
//
//func (a *Service) Equals(b *Service) bool {
//	if a.Id != b.Id {
//		return false
//	}
//	if a.Name != b.Name {
//		return false
//	}
//	if a.Context != b.Context {
//		return false
//	}
//	if a.Startup != b.Startup {
//		return false
//	}
//	if a.Description != b.Description {
//		return false
//	}
//	if a.Instances != b.Instances {
//		return false
//	}
//	if a.ImageId != b.ImageId {
//		return false
//	}
//	if a.PoolId != b.PoolId {
//		return false
//	}
//	if a.DesiredState != b.DesiredState {
//		return false
//	}
//	if a.Launch != b.Launch {
//		return false
//	}
//	if a.Hostname != b.Hostname {
//		return false
//	}
//	if a.Privileged != b.Privileged {
//		return false
//	}
//	if a.HostPolicy != b.HostPolicy {
//		return false
//	}
//	if a.ParentServiceId != b.ParentServiceId {
//		return false
//	}
//	if a.CreatedAt != b.CreatedAt {
//		return false
//	}
//	if a.UpdatedAt != b.CreatedAt {
//		return false
//	}
//	return true
//}
//
//func parent(cp ControlPlane) func(s Service) (value Service, err error) {
//	return func(s Service) (value Service, err error) {
//		err = cp.GetService(s.ParentServiceId, &value)
//		return
//	}
//}
//
//func context(cp ControlPlane) func(s Service) (ctx map[string]interface{}, err error) {
//	return func(s Service) (ctx map[string]interface{}, err error) {
//		err = json.Unmarshal([]byte(s.Context), &ctx)
//		if err != nil {
//			glog.Errorf("Error unmarshal service context Id=%s: %s -> %s", s.Id, s.Context, err)
//		}
//		return
//	}
//}
//
//// EvaluateActionsTemplate parses and evaluates the Actions string of a service.
//func (service *Service) EvaluateActionsTemplate(cp ControlPlane) (err error) {
//	for key, value := range service.Actions {
//		result := service.evaluateTemplate(cp, value)
//		if result != "" {
//			service.Actions[key] = result
//		}
//	}
//	return
//}
//
//// EvaluateStartupTemplate parses and evaluates the StartUp string of a service.
//func (service *Service) EvaluateStartupTemplate(cp ControlPlane) (err error) {
//
//	result := service.evaluateTemplate(cp, service.Startup)
//	if result != "" {
//		service.Startup = result
//	}
//
//	return
//}
//
//// EvaluateRunsTemplate parses and evaluates the Runs string of a service.
//func (service *Service) EvaluateRunsTemplate(cp ControlPlane) (err error) {
//	for key, value := range service.Runs {
//		result := service.evaluateTemplate(cp, value)
//		if result != "" {
//			service.Runs[key] = result
//		}
//	}
//	return
//}
//
//// evaluateTemplate takes a control plane client and template string and evaluates
//// the template using the service as the context. If the template is invalid or there is an error
//// then an empty string is returned.
//func (service *Service) evaluateTemplate(cp ControlPlane, serviceTemplate string) string {
//	functions := template.FuncMap{
//		"parent":  parent(cp),
//		"context": context(cp),
//	}
//	// parse the template
//	t := template.Must(template.New("ServiceDefinitionTemplate").Funcs(functions).Parse(serviceTemplate))
//
//	// evaluate it
//	var buffer bytes.Buffer
//	err := t.Execute(&buffer, service)
//	if err == nil {
//		return buffer.String()
//	}
//
//	// something went wrong, warn them
//	glog.Warning("Evaluating template %s produced the following error %s ", serviceTemplate, err)
//	return ""
//}
//
//// EvaluateLogConfigTemplate parses and evals the Path, Type and all the values for the tags of the log
//// configs. This happens for each LogConfig on the service.
//func (service *Service) EvaluateLogConfigTemplate(cp ControlPlane) (err error) {
//	// evaluate the template for the LogConfig as well as the tags
//
//	for i, logConfig := range service.LogConfigs {
//		// Path
//		result := service.evaluateTemplate(cp, logConfig.Path)
//		if result != "" {
//			service.LogConfigs[i].Path = result
//		}
//		// Type
//		result = service.evaluateTemplate(cp, logConfig.Type)
//		if result != "" {
//			service.LogConfigs[i].Type = result
//		}
//
//		// Tags
//		for j, tag := range logConfig.LogTags {
//			result = service.evaluateTemplate(cp, tag.Value)
//			if result != "" {
//				service.LogConfigs[i].LogTags[j].Value = result
//			}
//		}
//	}
//	return
//}
//
//// EvaluateEndpointTemplates parses and evaluates the "ApplicationTemplate" property
//// of each of the service endpoints for this service.
//func (service *Service) EvaluateEndpointTemplates(cp ControlPlane) (err error) {
//	functions := template.FuncMap{
//		"parent":  parent(cp),
//		"context": context(cp),
//	}
//
//	for i, ep := range service.Endpoints {
//		if ep.Application != "" && ep.ApplicationTemplate == "" {
//			ep.ApplicationTemplate = ep.Application
//			service.Endpoints[i].ApplicationTemplate = ep.Application
//		}
//		if ep.ApplicationTemplate != "" {
//			t := template.Must(template.New(service.Name).Funcs(functions).Parse(ep.ApplicationTemplate))
//			var buffer bytes.Buffer
//			if err = t.Execute(&buffer, service); err == nil {
//				service.Endpoints[i].Application = buffer.String()
//			} else {
//				return
//			}
//		}
//	}
//	return
//}
<commit_msg>delete file as part of Service move<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// 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 etcdv3

// BytesWatchPutResp is sent when new key-value pair has been inserted or the value is updated
type BytesWatchPutResp struct {
	key   string
	value []byte
	rev   int64
}

// NewBytesWatchPutResp creates an instance of BytesWatchPutResp
func NewBytesWatchPutResp(key string, value []byte, revision int64) *BytesWatchPutResp {
	return &BytesWatchPutResp{key: key, value: value, rev: revision}
}

// GetChangeType returns "Put" for BytesWatchPutResp
func (resp *BytesWatchPutResp) GetChangeType() datasync.PutDel {
	return datasync.Put
}

// GetKey returns the key that has been inserted
func (resp *BytesWatchPutResp) GetKey() string {
	return resp.key
}

// GetValue returns the value that has been inserted
func (resp *BytesWatchPutResp) GetValue() []byte {
	return resp.value
}

// GetRevision returns the revision associated with create action
func (resp *BytesWatchPutResp) GetRevision() int64 {
	return resp.rev
}

// BytesWatchDelResp is sent when a key-value pair has been removed
type BytesWatchDelResp struct {
	key string
	rev int64
}

// NewBytesWatchDelResp creates an instance of BytesWatchDelResp
func NewBytesWatchDelResp(key string, revision int64) *BytesWatchDelResp {
	return &BytesWatchDelResp{key: key, rev: revision}
}

// GetChangeType returns "Delete" for BytesWatchPutResp
func (resp *BytesWatchDelResp) GetChangeType() datasync.PutDel {
	return datasync.Delete
}

// GetKey returns the key that has been deleted
func (resp *BytesWatchDelResp) GetKey() string {
	return resp.key
}

// GetValue returns nil for BytesWatchDelResp
func (resp *BytesWatchDelResp) GetValue() []byte {
	return nil
}

// GetRevision returns the revision associated with the delete operation
func (resp *BytesWatchDelResp) GetRevision() int64 {
	return resp.rev
}
<commit_msg> ODPM-361 fix imports datasync.PutDel<commit_after>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// 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 etcdv3

import "github.com/ligato/cn-infra/datasync"

// BytesWatchPutResp is sent when new key-value pair has been inserted or the value is updated
type BytesWatchPutResp struct {
	key   string
	value []byte
	rev   int64
}

// NewBytesWatchPutResp creates an instance of BytesWatchPutResp
func NewBytesWatchPutResp(key string, value []byte, revision int64) *BytesWatchPutResp {
	return &BytesWatchPutResp{key: key, value: value, rev: revision}
}

// GetChangeType returns "Put" for BytesWatchPutResp
func (resp *BytesWatchPutResp) GetChangeType() datasync.PutDel {
	return datasync.Put
}

// GetKey returns the key that has been inserted
func (resp *BytesWatchPutResp) GetKey() string {
	return resp.key
}

// GetValue returns the value that has been inserted
func (resp *BytesWatchPutResp) GetValue() []byte {
	return resp.value
}

// GetRevision returns the revision associated with create action
func (resp *BytesWatchPutResp) GetRevision() int64 {
	return resp.rev
}

// BytesWatchDelResp is sent when a key-value pair has been removed
type BytesWatchDelResp struct {
	key string
	rev int64
}

// NewBytesWatchDelResp creates an instance of BytesWatchDelResp
func NewBytesWatchDelResp(key string, revision int64) *BytesWatchDelResp {
	return &BytesWatchDelResp{key: key, rev: revision}
}

// GetChangeType returns "Delete" for BytesWatchPutResp
func (resp *BytesWatchDelResp) GetChangeType() datasync.PutDel {
	return datasync.Delete
}

// GetKey returns the key that has been deleted
func (resp *BytesWatchDelResp) GetKey() string {
	return resp.key
}

// GetValue returns nil for BytesWatchDelResp
func (resp *BytesWatchDelResp) GetValue() []byte {
	return nil
}

// GetRevision returns the revision associated with the delete operation
func (resp *BytesWatchDelResp) GetRevision() int64 {
	return resp.rev
}
<|endoftext|>


<commit_before>package libnetwork

import (
	"fmt"
)

// ErrNoSuchNetwork is returned when a network query finds no result
type ErrNoSuchNetwork string

func (nsn ErrNoSuchNetwork) Error() string {
	return fmt.Sprintf("network %s not found", string(nsn))
}

// NotFound denotes the type of this error
func (nsn ErrNoSuchNetwork) NotFound() {}

// ErrNoSuchEndpoint is returned when an endpoint query finds no result
type ErrNoSuchEndpoint string

func (nse ErrNoSuchEndpoint) Error() string {
	return fmt.Sprintf("endpoint %s not found", string(nse))
}

// NotFound denotes the type of this error
func (nse ErrNoSuchEndpoint) NotFound() {}

// ErrInvalidNetworkDriver is returned if an invalid driver
// name is passed.
type ErrInvalidNetworkDriver string

func (ind ErrInvalidNetworkDriver) Error() string {
	return fmt.Sprintf("invalid driver bound to network: %s", string(ind))
}

// BadRequest denotes the type of this error
func (ind ErrInvalidNetworkDriver) BadRequest() {}

// ErrInvalidJoin is returned if a join is attempted on an endpoint
// which already has a container joined.
type ErrInvalidJoin struct{}

func (ij ErrInvalidJoin) Error() string {
	return "a container has already joined the endpoint"
}

// BadRequest denotes the type of this error
func (ij ErrInvalidJoin) BadRequest() {}

// ErrNoContainer is returned when the endpoint has no container
// attached to it.
type ErrNoContainer struct{}

func (nc ErrNoContainer) Error() string {
	return "no container is attached to the endpoint"
}

// Maskable denotes the type of this error
func (nc ErrNoContainer) Maskable() {}

// ErrInvalidID is returned when a query-by-id method is being invoked
// with an empty id parameter
type ErrInvalidID string

func (ii ErrInvalidID) Error() string {
	return fmt.Sprintf("invalid id: %s", string(ii))
}

// BadRequest denotes the type of this error
func (ii ErrInvalidID) BadRequest() {}

// ErrInvalidName is returned when a query-by-name or resource create method is
// invoked with an empty name parameter
type ErrInvalidName string

func (in ErrInvalidName) Error() string {
	return fmt.Sprintf("invalid name: %s", string(in))
}

// BadRequest denotes the type of this error
func (in ErrInvalidName) BadRequest() {}

// ErrInvalidConfigFile type is returned when an invalid LibNetwork config file is detected
type ErrInvalidConfigFile string

func (cf ErrInvalidConfigFile) Error() string {
	return fmt.Sprintf("Invalid Config file %q", string(cf))
}

// NetworkTypeError type is returned when the network type string is not
// known to libnetwork.
type NetworkTypeError string

func (nt NetworkTypeError) Error() string {
	return fmt.Sprintf("unknown driver %q", string(nt))
}

// NotFound denotes the type of this error
func (nt NetworkTypeError) NotFound() {}

// NetworkNameError is returned when a network with the same name already exists.
type NetworkNameError string

func (nnr NetworkNameError) Error() string {
	return fmt.Sprintf("network with name %s already exists", string(nnr))
}

// Forbidden denotes the type of this error
func (nnr NetworkNameError) Forbidden() {}

// UnknownNetworkError is returned when libnetwork could not find in its database
// a network with the same name and id.
type UnknownNetworkError struct {
	name string
	id   string
}

func (une *UnknownNetworkError) Error() string {
	return fmt.Sprintf("unknown network %s id %s", une.name, une.id)
}

// NotFound denotes the type of this error
func (une *UnknownNetworkError) NotFound() {}

// ActiveEndpointsError is returned when a network is deleted which has active
// endpoints in it.
type ActiveEndpointsError struct {
	name string
	id   string
}

func (aee *ActiveEndpointsError) Error() string {
	return fmt.Sprintf("network %s has active endpoints", aee.name)
}

// Forbidden denotes the type of this error
func (aee *ActiveEndpointsError) Forbidden() {}

// UnknownEndpointError is returned when libnetwork could not find in its database
// an endpoint with the same name and id.
type UnknownEndpointError struct {
	name string
	id   string
}

func (uee *UnknownEndpointError) Error() string {
	return fmt.Sprintf("unknown endpoint %s id %s", uee.name, uee.id)
}

// NotFound denotes the type of this error
func (uee *UnknownEndpointError) NotFound() {}

// ActiveContainerError is returned when an endpoint is deleted which has active
// containers attached to it.
type ActiveContainerError struct {
	name string
	id   string
}

func (ace *ActiveContainerError) Error() string {
	return fmt.Sprintf("endpoint with name %s id %s has active containers", ace.name, ace.id)
}

// Forbidden denotes the type of this error
func (ace *ActiveContainerError) Forbidden() {}

// InvalidContainerIDError is returned when an invalid container id is passed
// in Join/Leave
type InvalidContainerIDError string

func (id InvalidContainerIDError) Error() string {
	return fmt.Sprintf("invalid container id %s", string(id))
}

// BadRequest denotes the type of this error
func (id InvalidContainerIDError) BadRequest() {}

// ManagerRedirectError is returned when the request should be redirected to Manager
type ManagerRedirectError string

func (mr ManagerRedirectError) Error() string {
	return "Redirect the request to the manager"
}

// Maskable denotes the type of this error
func (mr ManagerRedirectError) Maskable() {}
<commit_msg>print name and id infomation  when  has active endpoints<commit_after>package libnetwork

import (
	"fmt"
)

// ErrNoSuchNetwork is returned when a network query finds no result
type ErrNoSuchNetwork string

func (nsn ErrNoSuchNetwork) Error() string {
	return fmt.Sprintf("network %s not found", string(nsn))
}

// NotFound denotes the type of this error
func (nsn ErrNoSuchNetwork) NotFound() {}

// ErrNoSuchEndpoint is returned when an endpoint query finds no result
type ErrNoSuchEndpoint string

func (nse ErrNoSuchEndpoint) Error() string {
	return fmt.Sprintf("endpoint %s not found", string(nse))
}

// NotFound denotes the type of this error
func (nse ErrNoSuchEndpoint) NotFound() {}

// ErrInvalidNetworkDriver is returned if an invalid driver
// name is passed.
type ErrInvalidNetworkDriver string

func (ind ErrInvalidNetworkDriver) Error() string {
	return fmt.Sprintf("invalid driver bound to network: %s", string(ind))
}

// BadRequest denotes the type of this error
func (ind ErrInvalidNetworkDriver) BadRequest() {}

// ErrInvalidJoin is returned if a join is attempted on an endpoint
// which already has a container joined.
type ErrInvalidJoin struct{}

func (ij ErrInvalidJoin) Error() string {
	return "a container has already joined the endpoint"
}

// BadRequest denotes the type of this error
func (ij ErrInvalidJoin) BadRequest() {}

// ErrNoContainer is returned when the endpoint has no container
// attached to it.
type ErrNoContainer struct{}

func (nc ErrNoContainer) Error() string {
	return "no container is attached to the endpoint"
}

// Maskable denotes the type of this error
func (nc ErrNoContainer) Maskable() {}

// ErrInvalidID is returned when a query-by-id method is being invoked
// with an empty id parameter
type ErrInvalidID string

func (ii ErrInvalidID) Error() string {
	return fmt.Sprintf("invalid id: %s", string(ii))
}

// BadRequest denotes the type of this error
func (ii ErrInvalidID) BadRequest() {}

// ErrInvalidName is returned when a query-by-name or resource create method is
// invoked with an empty name parameter
type ErrInvalidName string

func (in ErrInvalidName) Error() string {
	return fmt.Sprintf("invalid name: %s", string(in))
}

// BadRequest denotes the type of this error
func (in ErrInvalidName) BadRequest() {}

// ErrInvalidConfigFile type is returned when an invalid LibNetwork config file is detected
type ErrInvalidConfigFile string

func (cf ErrInvalidConfigFile) Error() string {
	return fmt.Sprintf("Invalid Config file %q", string(cf))
}

// NetworkTypeError type is returned when the network type string is not
// known to libnetwork.
type NetworkTypeError string

func (nt NetworkTypeError) Error() string {
	return fmt.Sprintf("unknown driver %q", string(nt))
}

// NotFound denotes the type of this error
func (nt NetworkTypeError) NotFound() {}

// NetworkNameError is returned when a network with the same name already exists.
type NetworkNameError string

func (nnr NetworkNameError) Error() string {
	return fmt.Sprintf("network with name %s already exists", string(nnr))
}

// Forbidden denotes the type of this error
func (nnr NetworkNameError) Forbidden() {}

// UnknownNetworkError is returned when libnetwork could not find in its database
// a network with the same name and id.
type UnknownNetworkError struct {
	name string
	id   string
}

func (une *UnknownNetworkError) Error() string {
	return fmt.Sprintf("unknown network %s id %s", une.name, une.id)
}

// NotFound denotes the type of this error
func (une *UnknownNetworkError) NotFound() {}

// ActiveEndpointsError is returned when a network is deleted which has active
// endpoints in it.
type ActiveEndpointsError struct {
	name string
	id   string
}

func (aee *ActiveEndpointsError) Error() string {
	return fmt.Sprintf("network %s id %s has active endpoints", aee.name, aee.id)
}

// Forbidden denotes the type of this error
func (aee *ActiveEndpointsError) Forbidden() {}

// UnknownEndpointError is returned when libnetwork could not find in its database
// an endpoint with the same name and id.
type UnknownEndpointError struct {
	name string
	id   string
}

func (uee *UnknownEndpointError) Error() string {
	return fmt.Sprintf("unknown endpoint %s id %s", uee.name, uee.id)
}

// NotFound denotes the type of this error
func (uee *UnknownEndpointError) NotFound() {}

// ActiveContainerError is returned when an endpoint is deleted which has active
// containers attached to it.
type ActiveContainerError struct {
	name string
	id   string
}

func (ace *ActiveContainerError) Error() string {
	return fmt.Sprintf("endpoint with name %s id %s has active containers", ace.name, ace.id)
}

// Forbidden denotes the type of this error
func (ace *ActiveContainerError) Forbidden() {}

// InvalidContainerIDError is returned when an invalid container id is passed
// in Join/Leave
type InvalidContainerIDError string

func (id InvalidContainerIDError) Error() string {
	return fmt.Sprintf("invalid container id %s", string(id))
}

// BadRequest denotes the type of this error
func (id InvalidContainerIDError) BadRequest() {}

// ManagerRedirectError is returned when the request should be redirected to Manager
type ManagerRedirectError string

func (mr ManagerRedirectError) Error() string {
	return "Redirect the request to the manager"
}

// Maskable denotes the type of this error
func (mr ManagerRedirectError) Maskable() {}
<|endoftext|>


<commit_before>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package manager

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"path"

	"github.com/webx-top/com"
	"github.com/webx-top/echo"
	"github.com/webx-top/echo/middleware/tplfunc"
	"github.com/webx-top/echo/param"

	"github.com/admpub/checksum"
	imageproxy "github.com/admpub/imageproxy"
	"github.com/admpub/log"
	"github.com/admpub/nging/application/handler"
	"github.com/admpub/nging/application/library/common"
	"github.com/admpub/nging/application/middleware"
	modelFile "github.com/admpub/nging/application/model/file"
	"github.com/admpub/nging/application/registry/upload"
)

// cropPermCheckers 裁剪权限检查
var cropPermCheckers = []func(ctx echo.Context, f *modelFile.File) error{
	func(ctx echo.Context, f *modelFile.File) error {
		if f.FieldName() == `avatar` && f.OwnerType == `user` {
			err := middleware.CheckAnyPerm(ctx, `manager/user_add`, `manager/user_edit`)
			if err != nil {
				return err
			}
			return nil
		}
		return common.ErrNext
	},
}

// CropPermCheckerAdd 添加裁剪权限检查逻辑
func CropPermCheckerAdd(checker func(ctx echo.Context, f *modelFile.File) error) {
	cropPermCheckers = append(cropPermCheckers, checker)
}

// Crop 图片裁剪
func Crop(ctx echo.Context) error {
	ownerType := `user`
	user := handler.User(ctx)
	var ownerID uint64
	if user != nil {
		ownerID = uint64(user.Id)
	}
	if ownerID < 1 {
		ctx.Data().SetError(ctx.E(`请先登录`))
		return ctx.Redirect(handler.URLFor(`/login`))
	}
	return CropByOwner(ctx, ownerType, ownerID)
}

// CropByOwner 图片裁剪
func CropByOwner(ctx echo.Context, ownerType string, ownerID uint64) error {
	var err error
	newStore := upload.StorerGet(StorerEngine)
	if newStore == nil {
		return ctx.E(`存储引擎“%s”未被登记`, StorerEngine)
	}
	uploadType := ctx.Param(`type`)
	if len(uploadType) == 0 {
		uploadType = ctx.Form(`type`)
	}
	cropSize := ctx.Form(`size`, `200x200`)
	typ, fieldName, _ := getTableInfo(uploadType)
	subdirInfo := upload.SubdirGet(typ)
	if subdirInfo == nil {
		return ctx.E(`“%s”未被登记`, uploadType)
	}
	thumbSizes := subdirInfo.ThumbSize(fieldName)
	var thumbSize *upload.ThumbSize
	if len(thumbSizes) > 0 {
		for _, ts := range thumbSizes {
			if ts.String() == cropSize {
				thumbSize = &ts
				break
			}
		}
		if thumbSize == nil {
			return ctx.E(`“%s”不支持裁剪图片`, uploadType)
		}
	}
	storer := newStore(ctx, typ)
	defer storer.Close()
	srcURL := ctx.Form(`src`)
	srcURL, err = com.URLDecode(srcURL)
	if err != nil {
		return err
	}
	if err = common.IsRightUploadFile(ctx, srcURL); err != nil {
		return err
	}
	thumbM := modelFile.NewThumb(ctx)
	fileM := modelFile.NewFile(ctx)
	err = fileM.GetByViewURL(StorerEngine, srcURL)
	if err != nil {
		return err
	}
	var editable bool
	if ownerType == `user` && ownerID == 1 { //管理员可编辑
		editable = true
	} else if fileM.OwnerType == ownerType &&
		fileM.OwnerId == ownerID { //上传者可编辑
		editable = true
	} else { //其它验证方式
		for _, check := range cropPermCheckers {
			err := check(ctx, fileM)
			if err == nil { //验证到权限
				editable = true
				break
			}
			if err != common.ErrNext {
				return err
			}
		}
	}
	if !editable {
		return common.ErrUserNoPerm
	}

	x := ctx.Formx(`x`).Float64()
	y := ctx.Formx(`y`).Float64()
	w := ctx.Formx(`w`).Float64()
	h := ctx.Formx(`h`).Float64()

	//{"x":528,"y":108,"height":864,"width":864,"rotate":0}
	//fmt.Println(avatard)
	opt := imageproxy.Options{
		CropX:          x,   //裁剪X轴起始位置
		CropY:          y,   //裁剪Y轴起始位置
		CropWidth:      w,   //裁剪宽度
		CropHeight:     h,   //裁剪高度
		Width:          200, //缩略图宽度
		Height:         200, //缩略图高度
		Fit:            false,
		Rotate:         0,
		FlipVertical:   false,
		FlipHorizontal: false,
		Quality:        100,
		Signature:      "",
		ScaleUp:        true,
	}
	if thumbSize != nil {
		opt.Width = thumbSize.Width
		opt.Height = thumbSize.Height
	}
	thumbURL := tplfunc.AddSuffix(srcURL, fmt.Sprintf(`_%v_%v`, opt.Width, opt.Height))
	var cropped bool
	cropped, err = storer.Exists(thumbURL)
	if err != nil {
		return err
	}
	name := path.Base(srcURL)
	var onSuccess func() string

	//对于头像图片，可以根据原图文件的md5值来判断是否需要重新生成缩略图
	if len(name) > 7 && name[0:7] == `avatar.` {
		md5file := path.Join(path.Dir(srcURL), `avatar.md5`)
		putFile := storer.URLToFile(md5file)
		onSuccess = func() string {
			reader, err := storer.Get(srcURL)
			if reader != nil {
				defer reader.Close()
			}
			if err != nil {
				log.Error(err)
				return ``
			}
			originMd5, err := checksum.MD5sumReader(reader)
			if err != nil {
				log.Error(err)
				return ``
			}
			size := len(originMd5)
			_, _, err = storer.Put(putFile, bytes.NewBufferString(originMd5), int64(size))
			if err != nil {
				log.Error(err)
			}
			return originMd5
		}

		if cropped {
			cropped, err = storer.Exists(md5file)
			if err != nil {
				return err
			}
		}

		if cropped {
			md5reader, err := storer.Get(md5file)
			if md5reader != nil {
				defer md5reader.Close()
			}
			if err != nil {
				return err
			}
			b, err := ioutil.ReadAll(md5reader)
			if err != nil {
				return err
			}
			reader, err := storer.Get(srcURL)
			if reader != nil {
				defer reader.Close()
			}
			originMd5, err := checksum.MD5sumReader(reader)
			if err != nil {
				return err
			}
			if string(b) == originMd5 {
				goto END
			}
			cropped = false
			onSuccess = func() string { //直接使用上面读到的md5
				size := len(originMd5)
				_, _, err = storer.Put(putFile, bytes.NewBufferString(originMd5), int64(size))
				if err != nil {
					log.Error(err)
				}
				return originMd5
			}
		}
	}

END:
	if cropped {
		if ctx.Format() == `json` {
			return ctx.JSON(ctx.Data().SetInfo(`skipped`).SetData(thumbURL))
		}
		return storer.SendFile(ctx, thumbURL)
	}

	var reader io.ReadCloser
	reader, err = storer.Get(srcURL)
	if reader != nil {
		defer reader.Close()
	}
	if err != nil {
		return err
	}

	b, err := ioutil.ReadAll(reader)
	if err != nil {
		return err
	}
	thumb, err := imageproxy.Transform(b, opt)
	if err != nil {
		return err
	}
	byteReader := bytes.NewReader(thumb)
	thumbM.SavePath, thumbM.ViewUrl, err = storer.Put(storer.URLToFile(thumbURL), byteReader, byteReader.Size()) //r-4;w-2;x-1
	if err != nil {
		return err
	}
	var fileMd5 string
	if onSuccess != nil {
		fileMd5 = onSuccess()
	} else {
		fileMd5, err = checksum.MD5sumReader(reader)
		if err != nil {
			return err
		}
	}
	size := len(thumb)
	thumbM.Size = uint64(size)
	thumbM.Width = param.AsUint(opt.Width)
	thumbM.Height = param.AsUint(opt.Height)
	thumbM.SaveName = path.Base(thumbM.SavePath)
	thumbM.UsedTimes = 0
	thumbM.Md5 = fileMd5
	err = thumbM.SetByFile(fileM.File).Save()
	if err != nil {
		return err
	}
	if ctx.Format() == `json` {
		return ctx.JSON(ctx.Data().SetInfo(`cropped`).SetData(thumbURL))
	}
	return storer.SendFile(ctx, thumbURL)
}
<commit_msg>update<commit_after>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package manager

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"path"
	"strings"

	"github.com/webx-top/com"
	"github.com/webx-top/echo"
	"github.com/webx-top/echo/middleware/tplfunc"
	"github.com/webx-top/echo/param"

	"github.com/admpub/checksum"
	imageproxy "github.com/admpub/imageproxy"
	"github.com/admpub/log"
	"github.com/admpub/nging/application/handler"
	"github.com/admpub/nging/application/library/common"
	"github.com/admpub/nging/application/middleware"
	modelFile "github.com/admpub/nging/application/model/file"
	"github.com/admpub/nging/application/registry/upload"
)

// cropPermCheckers 裁剪权限检查
var cropPermCheckers = []func(ctx echo.Context, f *modelFile.File) error{
	func(ctx echo.Context, f *modelFile.File) error {
		if f.FieldName() == `avatar` && f.OwnerType == `user` {
			err := middleware.CheckAnyPerm(ctx, `manager/user_add`, `manager/user_edit`)
			if err != nil {
				return err
			}
			return nil
		}
		return common.ErrNext
	},
}

// CropPermCheckerAdd 添加裁剪权限检查逻辑
func CropPermCheckerAdd(checker func(ctx echo.Context, f *modelFile.File) error) {
	cropPermCheckers = append(cropPermCheckers, checker)
}

// Crop 图片裁剪
func Crop(ctx echo.Context) error {
	ownerType := `user`
	user := handler.User(ctx)
	var ownerID uint64
	if user != nil {
		ownerID = uint64(user.Id)
	}
	if ownerID < 1 {
		ctx.Data().SetError(ctx.E(`请先登录`))
		return ctx.Redirect(handler.URLFor(`/login`))
	}
	return CropByOwner(ctx, ownerType, ownerID)
}

// CropByOwner 图片裁剪
func CropByOwner(ctx echo.Context, ownerType string, ownerID uint64) error {
	var err error
	newStore := upload.StorerGet(StorerEngine)
	if newStore == nil {
		return ctx.E(`存储引擎“%s”未被登记`, StorerEngine)
	}
	uploadType := ctx.Param(`type`)
	if len(uploadType) == 0 {
		uploadType = ctx.Form(`type`)
	}
	cropSize := ctx.Form(`size`, `200x200`)
	typ, fieldName, _ := getTableInfo(uploadType)
	subdirInfo := upload.SubdirGet(typ)
	if subdirInfo == nil {
		return ctx.E(`“%s”未被登记`, uploadType)
	}
	thumbSizes := subdirInfo.ThumbSize(fieldName)
	var thumbWidth, thumbHeight float64
	cropSizeArr := strings.SplitN(cropSize, `x`, 2)
	switch len(cropSizeArr) {
	case 2:
		cropSizeArr[1] = strings.TrimSpace(cropSizeArr[1])
		thumbHeight = param.AsFloat64(cropSizeArr[1])
		cropSizeArr[0] = strings.TrimSpace(cropSizeArr[0])
		thumbWidth = param.AsFloat64(cropSizeArr[0])
	case 1:
		cropSizeArr[0] = strings.TrimSpace(cropSizeArr[0])
		thumbWidth = param.AsFloat64(cropSizeArr[0])
		thumbHeight = thumbWidth
	}
	var thumbSize *upload.ThumbSize
	if len(thumbSizes) > 0 {
		for _, ts := range thumbSizes {
			if ts.Width == thumbWidth && ts.Height == thumbHeight {
				thumbSize = &ts
				break
			}
		}
		if thumbSize == nil {
			return ctx.E(`“%s”不支持裁剪图片`, uploadType)
		}
	}
	storer := newStore(ctx, typ)
	defer storer.Close()
	srcURL := ctx.Form(`src`)
	srcURL, err = com.URLDecode(srcURL)
	if err != nil {
		return err
	}
	if err = common.IsRightUploadFile(ctx, srcURL); err != nil {
		return err
	}
	thumbM := modelFile.NewThumb(ctx)
	fileM := modelFile.NewFile(ctx)
	err = fileM.GetByViewURL(StorerEngine, srcURL)
	if err != nil {
		return err
	}
	var editable bool
	if ownerType == `user` && ownerID == 1 { //管理员可编辑
		editable = true
	} else if fileM.OwnerType == ownerType &&
		fileM.OwnerId == ownerID { //上传者可编辑
		editable = true
	} else { //其它验证方式
		for _, check := range cropPermCheckers {
			err := check(ctx, fileM)
			if err == nil { //验证到权限
				editable = true
				break
			}
			if err != common.ErrNext {
				return err
			}
		}
	}
	if !editable {
		return common.ErrUserNoPerm
	}

	x := ctx.Formx(`x`).Float64()
	y := ctx.Formx(`y`).Float64()
	w := ctx.Formx(`w`).Float64()
	h := ctx.Formx(`h`).Float64()

	//{"x":528,"y":108,"height":864,"width":864,"rotate":0}
	//fmt.Println(avatard)
	opt := imageproxy.Options{
		CropX:          x,   //裁剪X轴起始位置
		CropY:          y,   //裁剪Y轴起始位置
		CropWidth:      w,   //裁剪宽度
		CropHeight:     h,   //裁剪高度
		Width:          200, //缩略图宽度
		Height:         200, //缩略图高度
		Fit:            false,
		Rotate:         0,
		FlipVertical:   false,
		FlipHorizontal: false,
		Quality:        100,
		Signature:      "",
		ScaleUp:        true,
	}
	if thumbSize != nil {
		opt.Width = thumbSize.Width
		opt.Height = thumbSize.Height
	}
	thumbURL := tplfunc.AddSuffix(srcURL, fmt.Sprintf(`_%v_%v`, opt.Width, opt.Height))
	var cropped bool
	cropped, err = storer.Exists(thumbURL)
	if err != nil {
		return err
	}
	name := path.Base(srcURL)
	var onSuccess func() string

	//对于头像图片，可以根据原图文件的md5值来判断是否需要重新生成缩略图
	if len(name) > 7 && name[0:7] == `avatar.` {
		md5file := path.Join(path.Dir(srcURL), `avatar.md5`)
		putFile := storer.URLToFile(md5file)
		onSuccess = func() string {
			reader, err := storer.Get(srcURL)
			if reader != nil {
				defer reader.Close()
			}
			if err != nil {
				log.Error(err)
				return ``
			}
			originMd5, err := checksum.MD5sumReader(reader)
			if err != nil {
				log.Error(err)
				return ``
			}
			size := len(originMd5)
			_, _, err = storer.Put(putFile, bytes.NewBufferString(originMd5), int64(size))
			if err != nil {
				log.Error(err)
			}
			return originMd5
		}

		if cropped {
			cropped, err = storer.Exists(md5file)
			if err != nil {
				return err
			}
		}

		if cropped {
			md5reader, err := storer.Get(md5file)
			if md5reader != nil {
				defer md5reader.Close()
			}
			if err != nil {
				return err
			}
			b, err := ioutil.ReadAll(md5reader)
			if err != nil {
				return err
			}
			reader, err := storer.Get(srcURL)
			if reader != nil {
				defer reader.Close()
			}
			originMd5, err := checksum.MD5sumReader(reader)
			if err != nil {
				return err
			}
			if string(b) == originMd5 {
				goto END
			}
			cropped = false
			onSuccess = func() string { //直接使用上面读到的md5
				size := len(originMd5)
				_, _, err = storer.Put(putFile, bytes.NewBufferString(originMd5), int64(size))
				if err != nil {
					log.Error(err)
				}
				return originMd5
			}
		}
	}

END:
	if cropped {
		if ctx.Format() == `json` {
			return ctx.JSON(ctx.Data().SetInfo(`skipped`).SetData(thumbURL))
		}
		return storer.SendFile(ctx, thumbURL)
	}

	var reader io.ReadCloser
	reader, err = storer.Get(srcURL)
	if reader != nil {
		defer reader.Close()
	}
	if err != nil {
		return err
	}

	b, err := ioutil.ReadAll(reader)
	if err != nil {
		return err
	}
	thumb, err := imageproxy.Transform(b, opt)
	if err != nil {
		return err
	}
	byteReader := bytes.NewReader(thumb)
	thumbM.SavePath, thumbM.ViewUrl, err = storer.Put(storer.URLToFile(thumbURL), byteReader, byteReader.Size()) //r-4;w-2;x-1
	if err != nil {
		return err
	}
	var fileMd5 string
	if onSuccess != nil {
		fileMd5 = onSuccess()
	} else {
		fileMd5, err = checksum.MD5sumReader(reader)
		if err != nil {
			return err
		}
	}
	size := len(thumb)
	thumbM.Size = uint64(size)
	thumbM.Width = param.AsUint(opt.Width)
	thumbM.Height = param.AsUint(opt.Height)
	thumbM.SaveName = path.Base(thumbM.SavePath)
	thumbM.UsedTimes = 0
	thumbM.Md5 = fileMd5
	err = thumbM.SetByFile(fileM.File).Save()
	if err != nil {
		return err
	}
	if ctx.Format() == `json` {
		return ctx.JSON(ctx.Data().SetInfo(`cropped`).SetData(thumbURL))
	}
	return storer.SendFile(ctx, thumbURL)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"crypto/sha1"
	"encoding/binary"
	"errors"
	"fmt"
	"golang.org/x/crypto/pbkdf2"
	"io"
	"os"
)

const keySize = 32
const nIterations = 4096

var hmacFun = sha1.New

var salt = [8]byte{20, 183, 239, 38, 44, 214, 22, 141}

type encryptionService struct {
	lockKey          []byte
	encryptedDataKey []byte
	backupDataKey    []byte
	reader           *bufio.Reader
}

func main() {
	s := &encryptionService{
		reader: bufio.NewReader(os.Stdin),
	}
	for {
		s.processCommand()
	}
}

func (s *encryptionService) readCommand() (byte, []byte) {
	var size uint16
	err := binary.Read(s.reader, binary.BigEndian, &size)
	if err != nil {
		processReadError(err)
	}
	if size < 1 {
		panic("Command is too short")
	}
	command, err := s.reader.ReadByte()
	if err != nil {
		processReadError(err)
	}
	if size == 1 {
		return command, nil
	}
	buf := make([]byte, size-1)
	n, err := s.reader.Read(buf)
	if err != nil {
		processReadError(err)
	}
	if uint16(n) != size-1 {
		panic("Error reading input")
	}
	return command, buf
}

func processReadError(err error) {
	if err == io.EOF {
		// parent died. close normally
		os.Exit(0)
	}
	panic(fmt.Sprintf("Error reading input %v", err))
}

func doReply(data []byte) {
	err := binary.Write(os.Stdout, binary.BigEndian, uint16(len(data)))
	if err != nil {
		panic(fmt.Sprintf("Error writing data %v", err))
	}
	os.Stdout.Write(data)
}

func replySuccessWithData(data []byte) {
	doReply(append([]byte{'S'}, data...))
}

func replySuccess() {
	doReply([]byte{'S'})
}

func replyError(error string) {
	doReply([]byte("E" + error))
}

func encodeKey(key []byte) []byte {
	if key == nil {
		return []byte{0}
	}
	return append([]byte{byte(len(key))}, key...)
}

func combineDataKeys(key1, key2 []byte) []byte {
	return append(encodeKey(key1), encodeKey(key2)...)
}

func (s *encryptionService) replySuccessWithDataKey() {
	replySuccessWithData(combineDataKeys(s.encryptedDataKey, s.backupDataKey))
}

func (s *encryptionService) processCommand() {
	command, data := s.readCommand()

	switch command {
	case 1:
		s.cmdSetPassword(data)
	case 2:
		s.cmdCreateDataKey()
	case 3:
		s.cmdSetDataKey(data)
	case 4:
		s.cmdGetDataKey()
	case 5:
		s.cmdEncrypt(data)
	case 6:
		s.cmdDecrypt(data)
	case 7:
		s.cmdChangePassword(data)
	case 8:
		s.cmdRotateDataKey()
	case 9:
		s.cmdClearBackupKey(data)
	default:
		panic(fmt.Sprintf("Unknown command %v", command))
	}
}

func (s *encryptionService) cmdSetPassword(data []byte) {
	s.lockKey = generateLockKey(data)
	replySuccess()
}

func (s *encryptionService) createDataKey() []byte {
	dataKey := make([]byte, keySize)
	if _, err := io.ReadFull(rand.Reader, dataKey); err != nil {
		panic(err.Error())
	}
	return encrypt(s.lockKey, dataKey)
}

func (s *encryptionService) cmdCreateDataKey() {
	if s.lockKey == nil {
		panic("Password was not set")
	}
	replySuccessWithData(combineDataKeys(s.createDataKey(), nil))
}

func readField(b []byte) ([]byte, []byte) {
	size := b[0]
	return b[1 : size+1], b[size+1:]
}

func (s *encryptionService) cmdSetDataKey(data []byte) {
	if s.lockKey == nil {
		panic("Password was not set")
	}
	encryptedDataKey, data := readField(data)
	backupDataKey, _ := readField(data)

	_, err := decrypt(s.lockKey, encryptedDataKey)
	if err != nil {
		replyError(err.Error())
		return
	}
	if len(backupDataKey) == 0 {
		s.backupDataKey = nil
	} else {
		_, err = decrypt(s.lockKey, backupDataKey)
		if err != nil {
			replyError(err.Error())
			return
		}
		s.backupDataKey = backupDataKey
	}
	s.encryptedDataKey = encryptedDataKey
	replySuccess()
}

func (s *encryptionService) cmdGetDataKey() {
	s.replySuccessWithDataKey()
}

func (s *encryptionService) cmdEncrypt(data []byte) {
	if s.lockKey == nil {
		panic("Password was not set")
	}
	dataKey, err := decrypt(s.lockKey, s.encryptedDataKey)
	if err != nil {
		replyError(err.Error())
		return
	}
	replySuccessWithData(encrypt(dataKey, data))
}

func (s *encryptionService) decryptWithKey(key []byte, data []byte) ([]byte, error) {
	if key == nil {
		return nil, errors.New("Unable to decrypt value")
	}
	dataKey, err := decrypt(s.lockKey, key)
	if err != nil {
		return nil, err
	}
	return decrypt(dataKey, data)
}

func (s *encryptionService) cmdDecrypt(data []byte) {
	if s.lockKey == nil {
		panic("Password was not set")
	}
	plaintext, err := s.decryptWithKey(s.encryptedDataKey, data)
	if err == nil {
		replySuccessWithData(plaintext)
		return
	}
	plaintext, err = s.decryptWithKey(s.backupDataKey, data)
	if err != nil {
		replyError(err.Error())
		return
	}
	replySuccessWithData(plaintext)
}

func (s *encryptionService) cmdChangePassword(data []byte) {
	if s.lockKey == nil {
		panic("Password was not set")
	}
	var backupDataKey []byte
	var err error
	if s.backupDataKey != nil {
		backupDataKey, err = decrypt(s.lockKey, s.backupDataKey)
		if err != nil {
			replyError(err.Error())
			return
		}
	}
	dataKey, err := decrypt(s.lockKey, s.encryptedDataKey)
	if err != nil {
		replyError(err.Error())
		return
	}
	s.lockKey = generateLockKey(data)
	s.encryptedDataKey = encrypt(s.lockKey, dataKey)
	if s.backupDataKey != nil {
		s.backupDataKey = encrypt(s.lockKey, backupDataKey)
	}
	s.replySuccessWithDataKey()
}

func (s *encryptionService) cmdRotateDataKey() {
	if s.lockKey == nil {
		panic("Password was not set")
	}
	if s.backupDataKey != nil {
		replyError("Data key rotation is in progress")
		return
	}
	s.backupDataKey = s.encryptedDataKey
	s.encryptedDataKey = s.createDataKey()
	s.replySuccessWithDataKey()
}

func (s *encryptionService) cmdClearBackupKey(keys []byte) {
	if !bytes.Equal(combineDataKeys(s.encryptedDataKey, s.backupDataKey), keys) {
		replyError("Key mismatch")
		return
	}
	if s.backupDataKey == nil {
		replySuccess()
		return
	}
	s.backupDataKey = nil
	s.replySuccessWithDataKey()
}

func generateLockKey(password []byte) []byte {
	return pbkdf2.Key(password, salt[:], nIterations, keySize, hmacFun)
}

func encrypt(key []byte, data []byte) []byte {
	encrypted := aesgcmEncrypt(key, data)
	return append([]byte{0}, encrypted...)
}

func decrypt(key []byte, data []byte) ([]byte, error) {
	if len(data) < 1 {
		return nil, errors.New("ciphertext is too short")
	}
	if data[0] != 0 {
		return nil, errors.New("unsupported cipher")
	}
	return aesgcmDecrypt(key, data[1:len(data)])
}

func aesgcmEncrypt(key []byte, data []byte) []byte {
	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err.Error())
	}
	aesgcm, err := cipher.NewGCM(block)
	if err != nil {
		panic(err.Error())
	}

	nonce := make([]byte, aesgcm.NonceSize())
	if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
		panic(err.Error())
	}
	return aesgcm.Seal(nonce[:aesgcm.NonceSize()], nonce, data, nil)
}

func aesgcmDecrypt(key []byte, data []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err.Error())
	}
	aesgcm, err := cipher.NewGCM(block)
	if err != nil {
		panic(err.Error())
	}

	if len(data) < aesgcm.NonceSize() {
		return nil, errors.New("ciphertext is too short")
	}
	nonce := data[:aesgcm.NonceSize()]
	data = data[aesgcm.NonceSize():]

	return aesgcm.Open(nil, nonce, data, nil)
}
<commit_msg>go fmt gosecrets<commit_after>package main

import (
	"bufio"
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"crypto/sha1"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"os"

	"golang.org/x/crypto/pbkdf2"
)

const keySize = 32
const nIterations = 4096

var hmacFun = sha1.New

var salt = [8]byte{20, 183, 239, 38, 44, 214, 22, 141}

type encryptionService struct {
	lockKey          []byte
	encryptedDataKey []byte
	backupDataKey    []byte
	reader           *bufio.Reader
}

func main() {
	s := &encryptionService{
		reader: bufio.NewReader(os.Stdin),
	}
	for {
		s.processCommand()
	}
}

func (s *encryptionService) readCommand() (byte, []byte) {
	var size uint16
	err := binary.Read(s.reader, binary.BigEndian, &size)
	if err != nil {
		processReadError(err)
	}
	if size < 1 {
		panic("Command is too short")
	}
	command, err := s.reader.ReadByte()
	if err != nil {
		processReadError(err)
	}
	if size == 1 {
		return command, nil
	}
	buf := make([]byte, size-1)
	n, err := s.reader.Read(buf)
	if err != nil {
		processReadError(err)
	}
	if uint16(n) != size-1 {
		panic("Error reading input")
	}
	return command, buf
}

func processReadError(err error) {
	if err == io.EOF {
		// parent died. close normally
		os.Exit(0)
	}
	panic(fmt.Sprintf("Error reading input %v", err))
}

func doReply(data []byte) {
	err := binary.Write(os.Stdout, binary.BigEndian, uint16(len(data)))
	if err != nil {
		panic(fmt.Sprintf("Error writing data %v", err))
	}
	os.Stdout.Write(data)
}

func replySuccessWithData(data []byte) {
	doReply(append([]byte{'S'}, data...))
}

func replySuccess() {
	doReply([]byte{'S'})
}

func replyError(error string) {
	doReply([]byte("E" + error))
}

func encodeKey(key []byte) []byte {
	if key == nil {
		return []byte{0}
	}
	return append([]byte{byte(len(key))}, key...)
}

func combineDataKeys(key1, key2 []byte) []byte {
	return append(encodeKey(key1), encodeKey(key2)...)
}

func (s *encryptionService) replySuccessWithDataKey() {
	replySuccessWithData(combineDataKeys(s.encryptedDataKey, s.backupDataKey))
}

func (s *encryptionService) processCommand() {
	command, data := s.readCommand()

	switch command {
	case 1:
		s.cmdSetPassword(data)
	case 2:
		s.cmdCreateDataKey()
	case 3:
		s.cmdSetDataKey(data)
	case 4:
		s.cmdGetDataKey()
	case 5:
		s.cmdEncrypt(data)
	case 6:
		s.cmdDecrypt(data)
	case 7:
		s.cmdChangePassword(data)
	case 8:
		s.cmdRotateDataKey()
	case 9:
		s.cmdClearBackupKey(data)
	default:
		panic(fmt.Sprintf("Unknown command %v", command))
	}
}

func (s *encryptionService) cmdSetPassword(data []byte) {
	s.lockKey = generateLockKey(data)
	replySuccess()
}

func (s *encryptionService) createDataKey() []byte {
	dataKey := make([]byte, keySize)
	if _, err := io.ReadFull(rand.Reader, dataKey); err != nil {
		panic(err.Error())
	}
	return encrypt(s.lockKey, dataKey)
}

func (s *encryptionService) cmdCreateDataKey() {
	if s.lockKey == nil {
		panic("Password was not set")
	}
	replySuccessWithData(combineDataKeys(s.createDataKey(), nil))
}

func readField(b []byte) ([]byte, []byte) {
	size := b[0]
	return b[1 : size+1], b[size+1:]
}

func (s *encryptionService) cmdSetDataKey(data []byte) {
	if s.lockKey == nil {
		panic("Password was not set")
	}
	encryptedDataKey, data := readField(data)
	backupDataKey, _ := readField(data)

	_, err := decrypt(s.lockKey, encryptedDataKey)
	if err != nil {
		replyError(err.Error())
		return
	}
	if len(backupDataKey) == 0 {
		s.backupDataKey = nil
	} else {
		_, err = decrypt(s.lockKey, backupDataKey)
		if err != nil {
			replyError(err.Error())
			return
		}
		s.backupDataKey = backupDataKey
	}
	s.encryptedDataKey = encryptedDataKey
	replySuccess()
}

func (s *encryptionService) cmdGetDataKey() {
	s.replySuccessWithDataKey()
}

func (s *encryptionService) cmdEncrypt(data []byte) {
	if s.lockKey == nil {
		panic("Password was not set")
	}
	dataKey, err := decrypt(s.lockKey, s.encryptedDataKey)
	if err != nil {
		replyError(err.Error())
		return
	}
	replySuccessWithData(encrypt(dataKey, data))
}

func (s *encryptionService) decryptWithKey(key []byte, data []byte) ([]byte, error) {
	if key == nil {
		return nil, errors.New("Unable to decrypt value")
	}
	dataKey, err := decrypt(s.lockKey, key)
	if err != nil {
		return nil, err
	}
	return decrypt(dataKey, data)
}

func (s *encryptionService) cmdDecrypt(data []byte) {
	if s.lockKey == nil {
		panic("Password was not set")
	}
	plaintext, err := s.decryptWithKey(s.encryptedDataKey, data)
	if err == nil {
		replySuccessWithData(plaintext)
		return
	}
	plaintext, err = s.decryptWithKey(s.backupDataKey, data)
	if err != nil {
		replyError(err.Error())
		return
	}
	replySuccessWithData(plaintext)
}

func (s *encryptionService) cmdChangePassword(data []byte) {
	if s.lockKey == nil {
		panic("Password was not set")
	}
	var backupDataKey []byte
	var err error
	if s.backupDataKey != nil {
		backupDataKey, err = decrypt(s.lockKey, s.backupDataKey)
		if err != nil {
			replyError(err.Error())
			return
		}
	}
	dataKey, err := decrypt(s.lockKey, s.encryptedDataKey)
	if err != nil {
		replyError(err.Error())
		return
	}
	s.lockKey = generateLockKey(data)
	s.encryptedDataKey = encrypt(s.lockKey, dataKey)
	if s.backupDataKey != nil {
		s.backupDataKey = encrypt(s.lockKey, backupDataKey)
	}
	s.replySuccessWithDataKey()
}

func (s *encryptionService) cmdRotateDataKey() {
	if s.lockKey == nil {
		panic("Password was not set")
	}
	if s.backupDataKey != nil {
		replyError("Data key rotation is in progress")
		return
	}
	s.backupDataKey = s.encryptedDataKey
	s.encryptedDataKey = s.createDataKey()
	s.replySuccessWithDataKey()
}

func (s *encryptionService) cmdClearBackupKey(keys []byte) {
	if !bytes.Equal(combineDataKeys(s.encryptedDataKey, s.backupDataKey), keys) {
		replyError("Key mismatch")
		return
	}
	if s.backupDataKey == nil {
		replySuccess()
		return
	}
	s.backupDataKey = nil
	s.replySuccessWithDataKey()
}

func generateLockKey(password []byte) []byte {
	return pbkdf2.Key(password, salt[:], nIterations, keySize, hmacFun)
}

func encrypt(key []byte, data []byte) []byte {
	encrypted := aesgcmEncrypt(key, data)
	return append([]byte{0}, encrypted...)
}

func decrypt(key []byte, data []byte) ([]byte, error) {
	if len(data) < 1 {
		return nil, errors.New("ciphertext is too short")
	}
	if data[0] != 0 {
		return nil, errors.New("unsupported cipher")
	}
	return aesgcmDecrypt(key, data[1:len(data)])
}

func aesgcmEncrypt(key []byte, data []byte) []byte {
	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err.Error())
	}
	aesgcm, err := cipher.NewGCM(block)
	if err != nil {
		panic(err.Error())
	}

	nonce := make([]byte, aesgcm.NonceSize())
	if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
		panic(err.Error())
	}
	return aesgcm.Seal(nonce[:aesgcm.NonceSize()], nonce, data, nil)
}

func aesgcmDecrypt(key []byte, data []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err.Error())
	}
	aesgcm, err := cipher.NewGCM(block)
	if err != nil {
		panic(err.Error())
	}

	if len(data) < aesgcm.NonceSize() {
		return nil, errors.New("ciphertext is too short")
	}
	nonce := data[:aesgcm.NonceSize()]
	data = data[aesgcm.NonceSize():]

	return aesgcm.Open(nil, nonce, data, nil)
}
<|endoftext|>