<commit_before>package cli

import (
	"os"
	"testing"

	"github.com/juju/errgo"

	"github.com/giantswarm/inago/controller"
	"github.com/giantswarm/inago/file-system/fake"
)

type testFileSystemSetup struct {
	FileName    string
	FileContent []byte
	FilePerm    os.FileMode
}

func Test_Request_ExtendWithContent(t *testing.T) {
	testCases := []struct {
		Setup    []testFileSystemSetup
		Error    error
		Input    controller.Request
		Expected controller.Request
	}{
		// This test ensures that loading a single unit from a directory results in
		// the expected controller request.
		{
			Setup: []testFileSystemSetup{
				{
					FileName:    "dirname/dirname_unit.service",
					FileContent: []byte("some unit content"),
					FilePerm:    os.FileMode(0644),
				},
			},
			Error: nil,
			Input: controller.Request{
				RequestConfig: controller.RequestConfig{
					Group:    "dirname",
					SliceIDs: []string{},
				},
			},
			Expected: controller.Request{
				RequestConfig: controller.RequestConfig{
					SliceIDs: []string{},
				},
				Units: []controller.Unit{
					{
						Name:    "dirname_unit.service",
						Content: "some unit content",
					},
				},
			},
		},

		// This test ensures that extending an empty request does not inject
		// unwanted files.
		{
			Setup:    []testFileSystemSetup{},
			Error:    nil,
			Input:    controller.Request{},
			Expected: controller.Request{},
		},

		// This test ensures that trying to load unit files when no files are in
		// the file system throws an error.
		{
			Setup: []testFileSystemSetup{},
			Error: &os.PathError{
				Op:   "open",
				Path: "dirname",
				Err:  errgo.New("no such file or directory"),
			},
			Input: controller.Request{
				RequestConfig: controller.RequestConfig{
					Group:    "dirname",
					SliceIDs: []string{},
				},
			},
			Expected: controller.Request{},
		},
	}

	for i, testCase := range testCases {
		newFileSystem := filesystemfake.NewFileSystem()

		for _, setup := range testCase.Setup {
			err := newFileSystem.WriteFile(setup.FileName, setup.FileContent, setup.FilePerm)
			if err != nil {
				t.Fatal("case", i+1, "expected", nil, "got", err)
			}
		}

		output, err := extendRequestWithContent(newFileSystem, testCase.Input)
		if testCase.Error != nil && err.Error() != testCase.Error.Error() {
			t.Fatal("case", i+1, "expected", testCase.Error, "got", err)
		}

		if len(output.SliceIDs) != len(testCase.Expected.SliceIDs) {
			t.Fatal("case", i+1, "expected", len(testCase.Expected.SliceIDs), "got", len(output.SliceIDs))
		}

		for i, outputUnit := range output.Units {
			if outputUnit.Name != testCase.Expected.Units[i].Name {
				t.Fatal("case", i+1, "expected", testCase.Expected.Units[i].Name, "got", outputUnit.Name)
			}
		}
	}
}
<commit_msg>Add testcase for subfolders in groupfolder<commit_after>package cli

import (
	"os"
	"testing"

	"github.com/juju/errgo"

	"github.com/giantswarm/inago/controller"
	"github.com/giantswarm/inago/file-system/fake"
)

func givenSomeUnitFileContent() string {
	return "[Unit]\n" +
		"Description=Some Unit File Content\n" +
		"\n" +
		"[Service]\n" +
		"ExecStart=/bin/bash -c 'while true; do echo nothing to see, go along; done'\n"

}

type testFileSystemSetup struct {
	FileName    string
	FileContent []byte
	FilePerm    os.FileMode
}

func Test_Request_ExtendWithContent(t *testing.T) {
	testCases := []struct {
		Setup    []testFileSystemSetup
		Error    error
		Input    controller.Request
		Expected controller.Request
	}{
		// This test ensures that loading a single unit from a directory results in
		// the expected controller request.
		{
			Setup: []testFileSystemSetup{
				{
					FileName:    "dirname/dirname_unit.service",
					FileContent: []byte("some unit content"),
					FilePerm:    os.FileMode(0644),
				},
			},
			Error: nil,
			Input: controller.Request{
				RequestConfig: controller.RequestConfig{
					Group:    "dirname",
					SliceIDs: []string{},
				},
			},
			Expected: controller.Request{
				RequestConfig: controller.RequestConfig{
					SliceIDs: []string{},
				},
				Units: []controller.Unit{
					{
						Name:    "dirname_unit.service",
						Content: givenSomeUnitFileContent(),
					},
				},
			},
		},

		// This test ensures that extending an empty request does not inject
		// unwanted files.
		{
			Setup:    []testFileSystemSetup{},
			Error:    nil,
			Input:    controller.Request{},
			Expected: controller.Request{},
		},

		// This test ensures that trying to load unit files when no files are in
		// the file system throws an error.
		{
			Setup: []testFileSystemSetup{},
			Error: &os.PathError{
				Op:   "open",
				Path: "dirname",
				Err:  errgo.New("no such file or directory"),
			},
			Input: controller.Request{
				RequestConfig: controller.RequestConfig{
					Group:    "dirname",
					SliceIDs: []string{},
				},
			},
			Expected: controller.Request{},
		},

		// This test ensures that folders inside a group folder are ignored
		{
			Setup: []testFileSystemSetup{
				{FileName: "groupname/someotherdiretctory/REAMDE.md", FileContent: []byte("DO NOT READ ME"), FilePerm: os.FileMode(0644)},
				{FileName: "groupname/groupname-1.service", FileContent: []byte(givenSomeUnitFileContent()), FilePerm: os.FileMode(0644)},
				{FileName: "groupname/groupname-2.service", FileContent: []byte(givenSomeUnitFileContent()), FilePerm: os.FileMode(0644)},
			},
			Input: controller.Request{
				RequestConfig: controller.RequestConfig{
					Group: "groupname",
				},
			},
			Expected: controller.Request{
				Units: []controller.Unit{
					{
						Name:    "groupname-1.service",
						Content: givenSomeUnitFileContent(),
					},
					{
						Name:    "groupname-2.service",
						Content: givenSomeUnitFileContent(),
					},
				},
			},
		},
	}

	for i, testCase := range testCases {
		newFileSystem := filesystemfake.NewFileSystem()

		for _, setup := range testCase.Setup {
			err := newFileSystem.WriteFile(setup.FileName, setup.FileContent, setup.FilePerm)
			if err != nil {
				t.Fatal("case", i+1, "expected", nil, "got", err)
			}
		}

		output, err := extendRequestWithContent(newFileSystem, testCase.Input)
		if testCase.Error != nil && err.Error() != testCase.Error.Error() {
			t.Fatal("case", i+1, "expected", testCase.Error, "got", err)
		}

		if len(output.SliceIDs) != len(testCase.Expected.SliceIDs) {
			t.Fatal("case", i+1, "expected", len(testCase.Expected.SliceIDs), "got", len(output.SliceIDs))
		}

		if len(output.Units) != len(testCase.Expected.Units) {
			t.Fatalf("case %d: expected %d units in output, got %d", i+1, len(testCase.Expected.Units), len(output.Units))
		}
		for j, outputUnit := range output.Units {
			if outputUnit.Name != testCase.Expected.Units[j].Name {
				t.Fatalf("case %d: expected %s, got %s", i+1, testCase.Expected.Units[j].Name, outputUnit.Name)
			}
		}
	}
}
<|endoftext|>


<commit_before>// +build acceptance

package v2

import (
	"fmt"
	"os"
	"testing"

	"github.com/rackspace/gophercloud"
	"github.com/rackspace/gophercloud/acceptance/tools"
	"github.com/rackspace/gophercloud/openstack"
	"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
	"github.com/rackspace/gophercloud/openstack/networking/v2/networks"
	"github.com/rackspace/gophercloud/openstack/utils"
	"github.com/rackspace/gophercloud/pagination"
)

func TestListServers(t *testing.T) {
	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	t.Logf("ID\tRegion\tName\tStatus\tIPv4\tIPv6")

	pager := servers.List(client, servers.ListOpts{})
	count, pages := 0, 0
	pager.EachPage(func(page pagination.Page) (bool, error) {
		pages++
		t.Logf("---")

		servers, err := servers.ExtractServers(page)
		if err != nil {
			return false, err
		}

		for _, s := range servers {
			t.Logf("%s\t%s\t%s\t%s\t%s\t\n", s.ID, s.Name, s.Status, s.AccessIPv4, s.AccessIPv6)
			count++
		}

		return true, nil
	})

	fmt.Printf("--------\n%d servers listed on %d pages.\n", count, pages)
}

func networkingClient() (*gophercloud.ServiceClient, error) {
	opts, err := utils.AuthOptions()
	if err != nil {
		return nil, err
	}

	provider, err := openstack.AuthenticatedClient(opts)
	if err != nil {
		return nil, err
	}

	return openstack.NewNetworkV2(provider, gophercloud.EndpointOpts{
		Name:   "neutron",
		Region: os.Getenv("OS_REGION_NAME"),
	})
}

func createServer(t *testing.T, client *gophercloud.ServiceClient, choices *ComputeChoices) (*servers.Server, error) {
	var network networks.Network

	networkingClient, err := networkingClient()
	if err != nil {
		t.Fatalf("Unable to create a networking client: %v", err)
	}

	pager := networks.List(networkingClient, networks.ListOpts{Name: "public", Limit: 1})
	pager.EachPage(func(page pagination.Page) (bool, error) {
		networks, err := networks.ExtractNetworks(page)
		if err != nil {
			t.Errorf("Failed to extract networks: %v", err)
			return false, err
		}

		if len(networks) == 0 {
			t.Errorf("No networks to attach to server")
			return false, err
		}

		network = networks[0]

		return false, nil
	})

	name := tools.RandomString("ACPTTEST", 16)
	t.Logf("Attempting to create server: %s\n", name)

	server, err := servers.Create(client, servers.CreateOpts{
		Name:      name,
		FlavorRef: choices.FlavorID,
		ImageRef:  choices.ImageID,
		Networks: []servers.Network{
			servers.Network{UUID: network.ID},
		},
	}).Extract()
	if err != nil {
		t.Fatalf("Unable to create server: %v", err)
	}

	return server, err
}

func TestCreateDestroyServer(t *testing.T) {
	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatalf("Unable to create server: %v", err)
	}
	defer func() {
		servers.Delete(client, server.ID)
		t.Logf("Server deleted.")
	}()

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatalf("Unable to wait for server: %v", err)
	}
}

func TestUpdateServer(t *testing.T) {
	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatal(err)
	}
	defer servers.Delete(client, server.ID)

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}

	alternateName := tools.RandomString("ACPTTEST", 16)
	for alternateName == server.Name {
		alternateName = tools.RandomString("ACPTTEST", 16)
	}

	t.Logf("Attempting to rename the server to %s.", alternateName)

	updated, err := servers.Update(client, server.ID, servers.UpdateOpts{Name: alternateName}).Extract()
	if err != nil {
		t.Fatalf("Unable to rename server: %v", err)
	}

	if updated.ID != server.ID {
		t.Errorf("Updated server ID [%s] didn't match original server ID [%s]!", updated.ID, server.ID)
	}

	err = tools.WaitFor(func() (bool, error) {
		latest, err := servers.Get(client, updated.ID).Extract()
		if err != nil {
			return false, err
		}

		return latest.Name == alternateName, nil
	})
}

func TestActionChangeAdminPassword(t *testing.T) {
	t.Parallel()

	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatal(err)
	}
	defer servers.Delete(client, server.ID)

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}

	randomPassword := tools.MakeNewPassword(server.AdminPass)
	res := servers.ChangeAdminPassword(client, server.ID, randomPassword)
	if res.Err != nil {
		t.Fatal(err)
	}

	if err = waitForStatus(client, server, "PASSWORD"); err != nil {
		t.Fatal(err)
	}

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}
}

func TestActionReboot(t *testing.T) {
	t.Parallel()

	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatal(err)
	}
	defer servers.Delete(client, server.ID)

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}

	res := servers.Reboot(client, server.ID, "aldhjflaskhjf")
	if res.Err == nil {
		t.Fatal("Expected the SDK to provide an ArgumentError here")
	}

	t.Logf("Attempting reboot of server %s", server.ID)
	res = servers.Reboot(client, server.ID, servers.OSReboot)
	if res.Err != nil {
		t.Fatalf("Unable to reboot server: %v", err)
	}

	if err = waitForStatus(client, server, "REBOOT"); err != nil {
		t.Fatal(err)
	}

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}
}

func TestActionRebuild(t *testing.T) {
	t.Parallel()

	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatal(err)
	}
	defer servers.Delete(client, server.ID)

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}

	t.Logf("Attempting to rebuild server %s", server.ID)

	rebuildOpts := servers.RebuildOpts{
		Name:      tools.RandomString("ACPTTEST", 16),
		AdminPass: tools.MakeNewPassword(server.AdminPass),
		ImageID:   choices.ImageID,
	}

	rebuilt, err := servers.Rebuild(client, server.ID, rebuildOpts).Extract()
	if err != nil {
		t.Fatal(err)
	}

	if rebuilt.ID != server.ID {
		t.Errorf("Expected rebuilt server ID of [%s]; got [%s]", server.ID, rebuilt.ID)
	}

	if err = waitForStatus(client, rebuilt, "REBUILD"); err != nil {
		t.Fatal(err)
	}

	if err = waitForStatus(client, rebuilt, "ACTIVE"); err != nil {
		t.Fatal(err)
	}
}

func resizeServer(t *testing.T, client *gophercloud.ServiceClient, server *servers.Server, choices *ComputeChoices) {
	if err := waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}

	t.Logf("Attempting to resize server [%s]", server.ID)

	if res := servers.Resize(client, server.ID, choices.FlavorIDResize); res.Err != nil {
		t.Fatal(res.Err)
	}

	if err := waitForStatus(client, server, "VERIFY_RESIZE"); err != nil {
		t.Fatal(err)
	}
}

func TestActionResizeConfirm(t *testing.T) {
	t.Parallel()

	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatal(err)
	}
	defer servers.Delete(client, server.ID)
	resizeServer(t, client, server, choices)

	t.Logf("Attempting to confirm resize for server %s", server.ID)

	if res := servers.ConfirmResize(client, server.ID); res.Err != nil {
		t.Fatal(err)
	}

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}
}

func TestActionResizeRevert(t *testing.T) {
	t.Parallel()

	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatal(err)
	}
	defer servers.Delete(client, server.ID)
	resizeServer(t, client, server, choices)

	t.Logf("Attempting to revert resize for server %s", server.ID)

	if res := servers.RevertResize(client, server.ID); res.Err != nil {
		t.Fatal(err)
	}

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}
}
<commit_msg>t.Errorf -> t.Fatalf<commit_after>// +build acceptance

package v2

import (
	"fmt"
	"os"
	"testing"

	"github.com/rackspace/gophercloud"
	"github.com/rackspace/gophercloud/acceptance/tools"
	"github.com/rackspace/gophercloud/openstack"
	"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
	"github.com/rackspace/gophercloud/openstack/networking/v2/networks"
	"github.com/rackspace/gophercloud/openstack/utils"
	"github.com/rackspace/gophercloud/pagination"
)

func TestListServers(t *testing.T) {
	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	t.Logf("ID\tRegion\tName\tStatus\tIPv4\tIPv6")

	pager := servers.List(client, servers.ListOpts{})
	count, pages := 0, 0
	pager.EachPage(func(page pagination.Page) (bool, error) {
		pages++
		t.Logf("---")

		servers, err := servers.ExtractServers(page)
		if err != nil {
			return false, err
		}

		for _, s := range servers {
			t.Logf("%s\t%s\t%s\t%s\t%s\t\n", s.ID, s.Name, s.Status, s.AccessIPv4, s.AccessIPv6)
			count++
		}

		return true, nil
	})

	fmt.Printf("--------\n%d servers listed on %d pages.\n", count, pages)
}

func networkingClient() (*gophercloud.ServiceClient, error) {
	opts, err := utils.AuthOptions()
	if err != nil {
		return nil, err
	}

	provider, err := openstack.AuthenticatedClient(opts)
	if err != nil {
		return nil, err
	}

	return openstack.NewNetworkV2(provider, gophercloud.EndpointOpts{
		Name:   "neutron",
		Region: os.Getenv("OS_REGION_NAME"),
	})
}

func createServer(t *testing.T, client *gophercloud.ServiceClient, choices *ComputeChoices) (*servers.Server, error) {
	var network networks.Network

	networkingClient, err := networkingClient()
	if err != nil {
		t.Fatalf("Unable to create a networking client: %v", err)
	}

	pager := networks.List(networkingClient, networks.ListOpts{Name: "public", Limit: 1})
	pager.EachPage(func(page pagination.Page) (bool, error) {
		networks, err := networks.ExtractNetworks(page)
		if err != nil {
			t.Errorf("Failed to extract networks: %v", err)
			return false, err
		}

		if len(networks) == 0 {
			t.Fatalf("No networks to attach to server")
			return false, err
		}

		network = networks[0]

		return false, nil
	})

	name := tools.RandomString("ACPTTEST", 16)
	t.Logf("Attempting to create server: %s\n", name)

	server, err := servers.Create(client, servers.CreateOpts{
		Name:      name,
		FlavorRef: choices.FlavorID,
		ImageRef:  choices.ImageID,
		Networks: []servers.Network{
			servers.Network{UUID: network.ID},
		},
	}).Extract()
	if err != nil {
		t.Fatalf("Unable to create server: %v", err)
	}

	return server, err
}

func TestCreateDestroyServer(t *testing.T) {
	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatalf("Unable to create server: %v", err)
	}
	defer func() {
		servers.Delete(client, server.ID)
		t.Logf("Server deleted.")
	}()

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatalf("Unable to wait for server: %v", err)
	}
}

func TestUpdateServer(t *testing.T) {
	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatal(err)
	}
	defer servers.Delete(client, server.ID)

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}

	alternateName := tools.RandomString("ACPTTEST", 16)
	for alternateName == server.Name {
		alternateName = tools.RandomString("ACPTTEST", 16)
	}

	t.Logf("Attempting to rename the server to %s.", alternateName)

	updated, err := servers.Update(client, server.ID, servers.UpdateOpts{Name: alternateName}).Extract()
	if err != nil {
		t.Fatalf("Unable to rename server: %v", err)
	}

	if updated.ID != server.ID {
		t.Errorf("Updated server ID [%s] didn't match original server ID [%s]!", updated.ID, server.ID)
	}

	err = tools.WaitFor(func() (bool, error) {
		latest, err := servers.Get(client, updated.ID).Extract()
		if err != nil {
			return false, err
		}

		return latest.Name == alternateName, nil
	})
}

func TestActionChangeAdminPassword(t *testing.T) {
	t.Parallel()

	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatal(err)
	}
	defer servers.Delete(client, server.ID)

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}

	randomPassword := tools.MakeNewPassword(server.AdminPass)
	res := servers.ChangeAdminPassword(client, server.ID, randomPassword)
	if res.Err != nil {
		t.Fatal(err)
	}

	if err = waitForStatus(client, server, "PASSWORD"); err != nil {
		t.Fatal(err)
	}

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}
}

func TestActionReboot(t *testing.T) {
	t.Parallel()

	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatal(err)
	}
	defer servers.Delete(client, server.ID)

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}

	res := servers.Reboot(client, server.ID, "aldhjflaskhjf")
	if res.Err == nil {
		t.Fatal("Expected the SDK to provide an ArgumentError here")
	}

	t.Logf("Attempting reboot of server %s", server.ID)
	res = servers.Reboot(client, server.ID, servers.OSReboot)
	if res.Err != nil {
		t.Fatalf("Unable to reboot server: %v", err)
	}

	if err = waitForStatus(client, server, "REBOOT"); err != nil {
		t.Fatal(err)
	}

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}
}

func TestActionRebuild(t *testing.T) {
	t.Parallel()

	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatal(err)
	}
	defer servers.Delete(client, server.ID)

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}

	t.Logf("Attempting to rebuild server %s", server.ID)

	rebuildOpts := servers.RebuildOpts{
		Name:      tools.RandomString("ACPTTEST", 16),
		AdminPass: tools.MakeNewPassword(server.AdminPass),
		ImageID:   choices.ImageID,
	}

	rebuilt, err := servers.Rebuild(client, server.ID, rebuildOpts).Extract()
	if err != nil {
		t.Fatal(err)
	}

	if rebuilt.ID != server.ID {
		t.Errorf("Expected rebuilt server ID of [%s]; got [%s]", server.ID, rebuilt.ID)
	}

	if err = waitForStatus(client, rebuilt, "REBUILD"); err != nil {
		t.Fatal(err)
	}

	if err = waitForStatus(client, rebuilt, "ACTIVE"); err != nil {
		t.Fatal(err)
	}
}

func resizeServer(t *testing.T, client *gophercloud.ServiceClient, server *servers.Server, choices *ComputeChoices) {
	if err := waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}

	t.Logf("Attempting to resize server [%s]", server.ID)

	if res := servers.Resize(client, server.ID, choices.FlavorIDResize); res.Err != nil {
		t.Fatal(res.Err)
	}

	if err := waitForStatus(client, server, "VERIFY_RESIZE"); err != nil {
		t.Fatal(err)
	}
}

func TestActionResizeConfirm(t *testing.T) {
	t.Parallel()

	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatal(err)
	}
	defer servers.Delete(client, server.ID)
	resizeServer(t, client, server, choices)

	t.Logf("Attempting to confirm resize for server %s", server.ID)

	if res := servers.ConfirmResize(client, server.ID); res.Err != nil {
		t.Fatal(err)
	}

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}
}

func TestActionResizeRevert(t *testing.T) {
	t.Parallel()

	choices, err := ComputeChoicesFromEnv()
	if err != nil {
		t.Fatal(err)
	}

	client, err := newClient()
	if err != nil {
		t.Fatalf("Unable to create a compute client: %v", err)
	}

	server, err := createServer(t, client, choices)
	if err != nil {
		t.Fatal(err)
	}
	defer servers.Delete(client, server.ID)
	resizeServer(t, client, server, choices)

	t.Logf("Attempting to revert resize for server %s", server.ID)

	if res := servers.RevertResize(client, server.ID); res.Err != nil {
		t.Fatal(err)
	}

	if err = waitForStatus(client, server, "ACTIVE"); err != nil {
		t.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package commands

import (
	"context"
	"encoding/binary"
	"fmt"
	"io"
	"net/http"
	"sync"
	"time"

	core "github.com/ipfs/go-ipfs/core"

	floodsub "gx/ipfs/QmSFihvoND3eDaAYRCeLgLPt62yCPgMZs1NSZmKFEtJQQw/go-libp2p-floodsub"
	pstore "gx/ipfs/QmXauCuJzmzapetmC6W4TuDJLL1yFFrVzSHoWv8YdbmnxH/go-libp2p-peerstore"
	cmds "gx/ipfs/QmabLouZTZwhfALuBcssPvkzhbYGMb4394huT7HY4LQ6d3/go-ipfs-cmds"
	cid "gx/ipfs/QmcZfnkapfECQGcLZaf9B79NRg7cRa9EnZh4LSbkCzwNvY/go-cid"
	cmdkit "gx/ipfs/QmceUdzxkimdYsgtX733uNgzf1DLHyBKN6ehGSp85ayppM/go-ipfs-cmdkit"
	blocks "gx/ipfs/Qmej7nf81hi2x2tvjRBF3mcp74sQyuDH4VMYDGd1YtXjb2/go-block-format"
)

var PubsubCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "An experimental publish-subscribe system on ipfs.",
		ShortDescription: `
ipfs pubsub allows you to publish messages to a given topic, and also to
subscribe to new messages on a given topic.

This is an experimental feature. It is not intended in its current state
to be used in a production environment.

To use, the daemon must be run with '--enable-pubsub-experiment'.
`,
	},
	Subcommands: map[string]*cmds.Command{
		"pub":   PubsubPubCmd,
		"sub":   PubsubSubCmd,
		"ls":    PubsubLsCmd,
		"peers": PubsubPeersCmd,
	},
}

var PubsubSubCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "Subscribe to messages on a given topic.",
		ShortDescription: `
ipfs pubsub sub subscribes to messages on a given topic.

This is an experimental feature. It is not intended in its current state
to be used in a production environment.

To use, the daemon must be run with '--enable-pubsub-experiment'.
`,
		LongDescription: `
ipfs pubsub sub subscribes to messages on a given topic.

This is an experimental feature. It is not intended in its current state
to be used in a production environment.

To use, the daemon must be run with '--enable-pubsub-experiment'.

This command outputs data in the following encodings:
  * "json"
(Specified by the "--encoding" or "--enc" flag)
`,
	},
	Arguments: []cmdkit.Argument{
		cmdkit.StringArg("topic", true, false, "String name of topic to subscribe to."),
	},
	Options: []cmdkit.Option{
		cmdkit.BoolOption("discover", "try to discover other peers subscribed to the same topic"),
	},
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) {
		n, err := GetNode(env)
		if err != nil {
			res.SetError(err, cmdkit.ErrNormal)
			return
		}

		// Must be online!
		if !n.OnlineMode() {
			res.SetError(errNotOnline, cmdkit.ErrClient)
			return
		}

		if n.Floodsub == nil {
			res.SetError(fmt.Errorf("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use."), cmdkit.ErrNormal)
			return
		}

		topic := req.Arguments[0]
		sub, err := n.Floodsub.Subscribe(topic)
		if err != nil {
			res.SetError(err, cmdkit.ErrNormal)
			return
		}
		defer sub.Cancel()

		discover, _ := req.Options["discover"].(bool)
		if discover {
			go func() {
				blk := blocks.NewBlock([]byte("floodsub:" + topic))
				err := n.Blocks.AddBlock(blk)
				if err != nil {
					log.Error("pubsub discovery: ", err)
					return
				}

				connectToPubSubPeers(req.Context, n, blk.Cid())
			}()
		}

		if f, ok := res.(http.Flusher); ok {
			f.Flush()
		}

		for {
			msg, err := sub.Next(req.Context)
			if err == io.EOF || err == context.Canceled {
				return
			} else if err != nil {
				res.SetError(err, cmdkit.ErrNormal)
				return
			}

			res.Emit(msg)
		}
	},
	Encoders: cmds.EncoderMap{
		cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
			m, ok := v.(*floodsub.Message)
			if !ok {
				return fmt.Errorf("unexpected type: %T", v)
			}

			_, err := w.Write(m.Data)
			return err
		}),
		"ndpayload": cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
			m, ok := v.(*floodsub.Message)
			if !ok {
				return fmt.Errorf("unexpected type: %T", v)
			}

			m.Data = append(m.Data, '\n')
			_, err := w.Write(m.Data)
			return err
		}),
		"lenpayload": cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
			m, ok := v.(*floodsub.Message)
			if !ok {
				return fmt.Errorf("unexpected type: %T", v)
			}

			buf := make([]byte, 8, len(m.Data)+8)

			n := binary.PutUvarint(buf, uint64(len(m.Data)))
			buf = append(buf[:n], m.Data...)
			_, err := w.Write(buf)
			return err
		}),
	},
	Type: floodsub.Message{},
}

func connectToPubSubPeers(ctx context.Context, n *core.IpfsNode, cid *cid.Cid) {
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()

	provs := n.Routing.FindProvidersAsync(ctx, cid, 10)
	wg := &sync.WaitGroup{}
	for p := range provs {
		wg.Add(1)
		go func(pi pstore.PeerInfo) {
			defer wg.Done()
			ctx, cancel := context.WithTimeout(ctx, time.Second*10)
			defer cancel()
			err := n.PeerHost.Connect(ctx, pi)
			if err != nil {
				log.Info("pubsub discover: ", err)
				return
			}
			log.Info("connected to pubsub peer:", pi.ID)
		}(p)
	}

	wg.Wait()
}

var PubsubPubCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "Publish a message to a given pubsub topic.",
		ShortDescription: `
ipfs pubsub pub publishes a message to a specified topic.

This is an experimental feature. It is not intended in its current state
to be used in a production environment.

To use, the daemon must be run with '--enable-pubsub-experiment'.
`,
	},
	Arguments: []cmdkit.Argument{
		cmdkit.StringArg("topic", true, false, "Topic to publish to."),
		cmdkit.StringArg("data", true, true, "Payload of message to publish.").EnableStdin(),
	},
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) {
		n, err := GetNode(env)
		if err != nil {
			res.SetError(err, cmdkit.ErrNormal)
			return
		}

		// Must be online!
		if !n.OnlineMode() {
			res.SetError(errNotOnline, cmdkit.ErrClient)
			return
		}

		if n.Floodsub == nil {
			res.SetError("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use.", cmdkit.ErrNormal)
			return
		}

		topic := req.Arguments[0]

		err = req.ParseBodyArgs()
		if err != nil && !cmds.IsAllArgsAlreadyCovered(err) {
			res.SetError(err, cmdkit.ErrNormal)
			return
		}

		for _, data := range req.Arguments[1:] {
			if err := n.Floodsub.Publish(topic, []byte(data)); err != nil {
				res.SetError(err, cmdkit.ErrNormal)
				return
			}
		}
	},
}

var PubsubLsCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "List subscribed topics by name.",
		ShortDescription: `
ipfs pubsub ls lists out the names of topics you are currently subscribed to.

This is an experimental feature. It is not intended in its current state
to be used in a production environment.

To use, the daemon must be run with '--enable-pubsub-experiment'.
`,
	},
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) {
		n, err := GetNode(env)
		if err != nil {
			res.SetError(err, cmdkit.ErrNormal)
			return
		}

		// Must be online!
		if !n.OnlineMode() {
			res.SetError(errNotOnline, cmdkit.ErrClient)
			return
		}

		if n.Floodsub == nil {
			res.SetError("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use.", cmdkit.ErrNormal)
			return
		}

		for _, topic := range n.Floodsub.GetTopics() {
			res.Emit(topic)
		}
	},
	Type: "",
}

var PubsubPeersCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "List peers we are currently pubsubbing with.",
		ShortDescription: `
ipfs pubsub peers with no arguments lists out the pubsub peers you are
currently connected to. If given a topic, it will list connected
peers who are subscribed to the named topic.

This is an experimental feature. It is not intended in its current state
to be used in a production environment.

To use, the daemon must be run with '--enable-pubsub-experiment'.
`,
	},
	Arguments: []cmdkit.Argument{
		cmdkit.StringArg("topic", false, false, "topic to list connected peers of"),
	},
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) {
		n, err := GetNode(env)
		if err != nil {
			res.SetError(err, cmdkit.ErrNormal)
			return
		}

		// Must be online!
		if !n.OnlineMode() {
			res.SetError(errNotOnline, cmdkit.ErrClient)
			return
		}

		if n.Floodsub == nil {
			res.SetError(fmt.Errorf("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use."), cmdkit.ErrNormal)
			return
		}

		var topic string
		if len(req.Arguments) == 1 {
			topic = req.Arguments[0]
		}

		for _, peer := range n.Floodsub.ListPeers(topic) {
			res.Emit(peer.Pretty())
		}
	},
	Type: "",
	Encoders: cmds.EncoderMap{
		cmds.Text: cmds.Encoders[cmds.TextNewline],
	},
}
<commit_msg>cmd/pubsub: fix `pubsub ls` emiting plain strings instead of JSON<commit_after>package commands

import (
	"context"
	"encoding/binary"
	"fmt"
	"io"
	"net/http"
	"sync"
	"time"

	core "github.com/ipfs/go-ipfs/core"

	floodsub "gx/ipfs/QmSFihvoND3eDaAYRCeLgLPt62yCPgMZs1NSZmKFEtJQQw/go-libp2p-floodsub"
	pstore "gx/ipfs/QmXauCuJzmzapetmC6W4TuDJLL1yFFrVzSHoWv8YdbmnxH/go-libp2p-peerstore"
	cmds "gx/ipfs/QmabLouZTZwhfALuBcssPvkzhbYGMb4394huT7HY4LQ6d3/go-ipfs-cmds"
	cid "gx/ipfs/QmcZfnkapfECQGcLZaf9B79NRg7cRa9EnZh4LSbkCzwNvY/go-cid"
	cmdkit "gx/ipfs/QmceUdzxkimdYsgtX733uNgzf1DLHyBKN6ehGSp85ayppM/go-ipfs-cmdkit"
	blocks "gx/ipfs/Qmej7nf81hi2x2tvjRBF3mcp74sQyuDH4VMYDGd1YtXjb2/go-block-format"
)

var PubsubCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "An experimental publish-subscribe system on ipfs.",
		ShortDescription: `
ipfs pubsub allows you to publish messages to a given topic, and also to
subscribe to new messages on a given topic.

This is an experimental feature. It is not intended in its current state
to be used in a production environment.

To use, the daemon must be run with '--enable-pubsub-experiment'.
`,
	},
	Subcommands: map[string]*cmds.Command{
		"pub":   PubsubPubCmd,
		"sub":   PubsubSubCmd,
		"ls":    PubsubLsCmd,
		"peers": PubsubPeersCmd,
	},
}

var PubsubSubCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "Subscribe to messages on a given topic.",
		ShortDescription: `
ipfs pubsub sub subscribes to messages on a given topic.

This is an experimental feature. It is not intended in its current state
to be used in a production environment.

To use, the daemon must be run with '--enable-pubsub-experiment'.
`,
		LongDescription: `
ipfs pubsub sub subscribes to messages on a given topic.

This is an experimental feature. It is not intended in its current state
to be used in a production environment.

To use, the daemon must be run with '--enable-pubsub-experiment'.

This command outputs data in the following encodings:
  * "json"
(Specified by the "--encoding" or "--enc" flag)
`,
	},
	Arguments: []cmdkit.Argument{
		cmdkit.StringArg("topic", true, false, "String name of topic to subscribe to."),
	},
	Options: []cmdkit.Option{
		cmdkit.BoolOption("discover", "try to discover other peers subscribed to the same topic"),
	},
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) {
		n, err := GetNode(env)
		if err != nil {
			res.SetError(err, cmdkit.ErrNormal)
			return
		}

		// Must be online!
		if !n.OnlineMode() {
			res.SetError(errNotOnline, cmdkit.ErrClient)
			return
		}

		if n.Floodsub == nil {
			res.SetError(fmt.Errorf("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use."), cmdkit.ErrNormal)
			return
		}

		topic := req.Arguments[0]
		sub, err := n.Floodsub.Subscribe(topic)
		if err != nil {
			res.SetError(err, cmdkit.ErrNormal)
			return
		}
		defer sub.Cancel()

		discover, _ := req.Options["discover"].(bool)
		if discover {
			go func() {
				blk := blocks.NewBlock([]byte("floodsub:" + topic))
				err := n.Blocks.AddBlock(blk)
				if err != nil {
					log.Error("pubsub discovery: ", err)
					return
				}

				connectToPubSubPeers(req.Context, n, blk.Cid())
			}()
		}

		if f, ok := res.(http.Flusher); ok {
			f.Flush()
		}

		for {
			msg, err := sub.Next(req.Context)
			if err == io.EOF || err == context.Canceled {
				return
			} else if err != nil {
				res.SetError(err, cmdkit.ErrNormal)
				return
			}

			res.Emit(msg)
		}
	},
	Encoders: cmds.EncoderMap{
		cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
			m, ok := v.(*floodsub.Message)
			if !ok {
				return fmt.Errorf("unexpected type: %T", v)
			}

			_, err := w.Write(m.Data)
			return err
		}),
		"ndpayload": cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
			m, ok := v.(*floodsub.Message)
			if !ok {
				return fmt.Errorf("unexpected type: %T", v)
			}

			m.Data = append(m.Data, '\n')
			_, err := w.Write(m.Data)
			return err
		}),
		"lenpayload": cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
			m, ok := v.(*floodsub.Message)
			if !ok {
				return fmt.Errorf("unexpected type: %T", v)
			}

			buf := make([]byte, 8, len(m.Data)+8)

			n := binary.PutUvarint(buf, uint64(len(m.Data)))
			buf = append(buf[:n], m.Data...)
			_, err := w.Write(buf)
			return err
		}),
	},
	Type: floodsub.Message{},
}

func connectToPubSubPeers(ctx context.Context, n *core.IpfsNode, cid *cid.Cid) {
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()

	provs := n.Routing.FindProvidersAsync(ctx, cid, 10)
	wg := &sync.WaitGroup{}
	for p := range provs {
		wg.Add(1)
		go func(pi pstore.PeerInfo) {
			defer wg.Done()
			ctx, cancel := context.WithTimeout(ctx, time.Second*10)
			defer cancel()
			err := n.PeerHost.Connect(ctx, pi)
			if err != nil {
				log.Info("pubsub discover: ", err)
				return
			}
			log.Info("connected to pubsub peer:", pi.ID)
		}(p)
	}

	wg.Wait()
}

var PubsubPubCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "Publish a message to a given pubsub topic.",
		ShortDescription: `
ipfs pubsub pub publishes a message to a specified topic.

This is an experimental feature. It is not intended in its current state
to be used in a production environment.

To use, the daemon must be run with '--enable-pubsub-experiment'.
`,
	},
	Arguments: []cmdkit.Argument{
		cmdkit.StringArg("topic", true, false, "Topic to publish to."),
		cmdkit.StringArg("data", true, true, "Payload of message to publish.").EnableStdin(),
	},
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) {
		n, err := GetNode(env)
		if err != nil {
			res.SetError(err, cmdkit.ErrNormal)
			return
		}

		// Must be online!
		if !n.OnlineMode() {
			res.SetError(errNotOnline, cmdkit.ErrClient)
			return
		}

		if n.Floodsub == nil {
			res.SetError("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use.", cmdkit.ErrNormal)
			return
		}

		topic := req.Arguments[0]

		err = req.ParseBodyArgs()
		if err != nil && !cmds.IsAllArgsAlreadyCovered(err) {
			res.SetError(err, cmdkit.ErrNormal)
			return
		}

		for _, data := range req.Arguments[1:] {
			if err := n.Floodsub.Publish(topic, []byte(data)); err != nil {
				res.SetError(err, cmdkit.ErrNormal)
				return
			}
		}
	},
}

var PubsubLsCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "List subscribed topics by name.",
		ShortDescription: `
ipfs pubsub ls lists out the names of topics you are currently subscribed to.

This is an experimental feature. It is not intended in its current state
to be used in a production environment.

To use, the daemon must be run with '--enable-pubsub-experiment'.
`,
	},
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) {
		n, err := GetNode(env)
		if err != nil {
			res.SetError(err, cmdkit.ErrNormal)
			return
		}

		// Must be online!
		if !n.OnlineMode() {
			res.SetError(errNotOnline, cmdkit.ErrClient)
			return
		}

		if n.Floodsub == nil {
			res.SetError("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use.", cmdkit.ErrNormal)
			return
		}

		cmds.EmitOnce(res, stringList{n.Floodsub.GetTopics()})
	},
	Type: stringList{},
}

var PubsubPeersCmd = &cmds.Command{
	Helptext: cmdkit.HelpText{
		Tagline: "List peers we are currently pubsubbing with.",
		ShortDescription: `
ipfs pubsub peers with no arguments lists out the pubsub peers you are
currently connected to. If given a topic, it will list connected
peers who are subscribed to the named topic.

This is an experimental feature. It is not intended in its current state
to be used in a production environment.

To use, the daemon must be run with '--enable-pubsub-experiment'.
`,
	},
	Arguments: []cmdkit.Argument{
		cmdkit.StringArg("topic", false, false, "topic to list connected peers of"),
	},
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) {
		n, err := GetNode(env)
		if err != nil {
			res.SetError(err, cmdkit.ErrNormal)
			return
		}

		// Must be online!
		if !n.OnlineMode() {
			res.SetError(errNotOnline, cmdkit.ErrClient)
			return
		}

		if n.Floodsub == nil {
			res.SetError(fmt.Errorf("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use."), cmdkit.ErrNormal)
			return
		}

		var topic string
		if len(req.Arguments) == 1 {
			topic = req.Arguments[0]
		}

		for _, peer := range n.Floodsub.ListPeers(topic) {
			res.Emit(peer.Pretty())
		}
	},
	Type: "",
	Encoders: cmds.EncoderMap{
		cmds.Text: cmds.Encoders[cmds.TextNewline],
	},
}
<|endoftext|>


<commit_before>package commands

import (
	"bytes"
	"encoding/binary"
	"io"

	cmds "github.com/ipfs/go-ipfs/commands"

	floodsub "gx/ipfs/QmSWp1Yx7Z5pbpeCbUy6tfFj2DrHUe7tGQqyYC2vspbXH1/floodsub"
	u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
)

var PubsubCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "An experimental publish-subscribe system on ipfs.",
		ShortDescription: `
ipfs pubsub allows you to publish messages to a given topic, and also to
subscribe to new messages on a given topic.

This is an experimental feature. It is not intended in its current state
to be used in a production environment.
`,
	},
	Subcommands: map[string]*cmds.Command{
		"pub": PubsubPubCmd,
		"sub": PubsubSubCmd,
	},
}

var PubsubSubCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Subscribe to messages on a given topic.",
		ShortDescription: `
ipfs pubsub sub subscribes to messages on a given topic.

This is an experimental feature. It is not intended in its current state
to be used in a production environment.
`,
	},
	Arguments: []cmds.Argument{
		cmds.StringArg("topic", true, false, "String name of topic to subscribe to."),
	},
	Run: func(req cmds.Request, res cmds.Response) {
		n, err := req.InvocContext().GetNode()
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		// Must be online!
		if !n.OnlineMode() {
			res.SetError(errNotOnline, cmds.ErrClient)
			return
		}

		topic := req.Arguments()[0]
		msgs, err := n.Floodsub.Subscribe(topic)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		out := make(chan interface{})
		res.SetOutput((<-chan interface{})(out))

		ctx := req.Context()
		go func() {
			defer close(out)
			for {
				select {
				case msg, ok := <-msgs:
					if !ok {
						return
					}
					out <- msg
				case <-ctx.Done():
					n.Floodsub.Unsub(topic)
				}
			}
		}()
	},
	Marshalers: cmds.MarshalerMap{
		cmds.Text: getPsMsgMarshaler(func(m *floodsub.Message) (io.Reader, error) {
			log.Error("FROM: ", m.GetFrom())
			return bytes.NewReader(m.Data), nil
		}),
		"ndpayload": getPsMsgMarshaler(func(m *floodsub.Message) (io.Reader, error) {
			m.Data = append(m.Data, '\n')
			return bytes.NewReader(m.Data), nil
		}),
		"lenpayload": getPsMsgMarshaler(func(m *floodsub.Message) (io.Reader, error) {
			buf := make([]byte, 8)
			n := binary.PutUvarint(buf, uint64(len(m.Data)))
			return io.MultiReader(bytes.NewReader(buf[:n]), bytes.NewReader(m.Data)), nil
		}),
	},
	Type: floodsub.Message{},
}

func getPsMsgMarshaler(f func(m *floodsub.Message) (io.Reader, error)) func(cmds.Response) (io.Reader, error) {
	return func(res cmds.Response) (io.Reader, error) {
		outChan, ok := res.Output().(<-chan interface{})
		if !ok {
			return nil, u.ErrCast()
		}

		marshal := func(v interface{}) (io.Reader, error) {
			obj, ok := v.(*floodsub.Message)
			if !ok {
				return nil, u.ErrCast()
			}

			return f(obj)
		}

		return &cmds.ChannelMarshaler{
			Channel:   outChan,
			Marshaler: marshal,
			Res:       res,
		}, nil
	}
}

var PubsubPubCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Publish a message to a given pubsub topic.",
		ShortDescription: `
ipfs pubsub pub publishes a message to a specified topic.

This is an experimental feature. It is not intended in its current state
to be used in a production environment.
`,
	},
	Arguments: []cmds.Argument{
		cmds.StringArg("topic", true, false, "Topic to publish to."),
		cmds.StringArg("data", true, true, "Payload of message to publish.").EnableStdin(),
	},
	Options: []cmds.Option{},
	Run: func(req cmds.Request, res cmds.Response) {
		n, err := req.InvocContext().GetNode()
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		// Must be online!
		if !n.OnlineMode() {
			res.SetError(errNotOnline, cmds.ErrClient)
			return
		}

		topic := req.Arguments()[0]

		for _, data := range req.Arguments()[1:] {
			if err := n.Floodsub.Publish(topic, []byte(data)); err != nil {
				res.SetError(err, cmds.ErrNormal)
				return
			}
		}
	},
}
<commit_msg>remove debug log<commit_after>package commands

import (
	"bytes"
	"encoding/binary"
	"io"

	cmds "github.com/ipfs/go-ipfs/commands"

	floodsub "gx/ipfs/QmSWp1Yx7Z5pbpeCbUy6tfFj2DrHUe7tGQqyYC2vspbXH1/floodsub"
	u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
)

var PubsubCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "An experimental publish-subscribe system on ipfs.",
		ShortDescription: `
ipfs pubsub allows you to publish messages to a given topic, and also to
subscribe to new messages on a given topic.

This is an experimental feature. It is not intended in its current state
to be used in a production environment.
`,
	},
	Subcommands: map[string]*cmds.Command{
		"pub": PubsubPubCmd,
		"sub": PubsubSubCmd,
	},
}

var PubsubSubCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Subscribe to messages on a given topic.",
		ShortDescription: `
ipfs pubsub sub subscribes to messages on a given topic.

This is an experimental feature. It is not intended in its current state
to be used in a production environment.
`,
	},
	Arguments: []cmds.Argument{
		cmds.StringArg("topic", true, false, "String name of topic to subscribe to."),
	},
	Run: func(req cmds.Request, res cmds.Response) {
		n, err := req.InvocContext().GetNode()
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		// Must be online!
		if !n.OnlineMode() {
			res.SetError(errNotOnline, cmds.ErrClient)
			return
		}

		topic := req.Arguments()[0]
		msgs, err := n.Floodsub.Subscribe(topic)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		out := make(chan interface{})
		res.SetOutput((<-chan interface{})(out))

		ctx := req.Context()
		go func() {
			defer close(out)
			for {
				select {
				case msg, ok := <-msgs:
					if !ok {
						return
					}
					out <- msg
				case <-ctx.Done():
					n.Floodsub.Unsub(topic)
				}
			}
		}()
	},
	Marshalers: cmds.MarshalerMap{
		cmds.Text: getPsMsgMarshaler(func(m *floodsub.Message) (io.Reader, error) {
			return bytes.NewReader(m.Data), nil
		}),
		"ndpayload": getPsMsgMarshaler(func(m *floodsub.Message) (io.Reader, error) {
			m.Data = append(m.Data, '\n')
			return bytes.NewReader(m.Data), nil
		}),
		"lenpayload": getPsMsgMarshaler(func(m *floodsub.Message) (io.Reader, error) {
			buf := make([]byte, 8)
			n := binary.PutUvarint(buf, uint64(len(m.Data)))
			return io.MultiReader(bytes.NewReader(buf[:n]), bytes.NewReader(m.Data)), nil
		}),
	},
	Type: floodsub.Message{},
}

func getPsMsgMarshaler(f func(m *floodsub.Message) (io.Reader, error)) func(cmds.Response) (io.Reader, error) {
	return func(res cmds.Response) (io.Reader, error) {
		outChan, ok := res.Output().(<-chan interface{})
		if !ok {
			return nil, u.ErrCast()
		}

		marshal := func(v interface{}) (io.Reader, error) {
			obj, ok := v.(*floodsub.Message)
			if !ok {
				return nil, u.ErrCast()
			}

			return f(obj)
		}

		return &cmds.ChannelMarshaler{
			Channel:   outChan,
			Marshaler: marshal,
			Res:       res,
		}, nil
	}
}

var PubsubPubCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Publish a message to a given pubsub topic.",
		ShortDescription: `
ipfs pubsub pub publishes a message to a specified topic.

This is an experimental feature. It is not intended in its current state
to be used in a production environment.
`,
	},
	Arguments: []cmds.Argument{
		cmds.StringArg("topic", true, false, "Topic to publish to."),
		cmds.StringArg("data", true, true, "Payload of message to publish.").EnableStdin(),
	},
	Options: []cmds.Option{},
	Run: func(req cmds.Request, res cmds.Response) {
		n, err := req.InvocContext().GetNode()
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		// Must be online!
		if !n.OnlineMode() {
			res.SetError(errNotOnline, cmds.ErrClient)
			return
		}

		topic := req.Arguments()[0]

		for _, data := range req.Arguments()[1:] {
			if err := n.Floodsub.Publish(topic, []byte(data)); err != nil {
				res.SetError(err, cmds.ErrNormal)
				return
			}
		}
	},
}
<|endoftext|>


<commit_before>package arn

import (
	"sort"
	"strings"

	"github.com/fatih/color"
)

// SoundTrack ...
type SoundTrack struct {
	ID        string           `json:"id"`
	Media     []*ExternalMedia `json:"media"`
	Tags      []string         `json:"tags"`
	Likes     []string         `json:"likes"`
	Created   string           `json:"created"`
	CreatedBy string           `json:"createdBy"`
	Edited    string           `json:"edited"`

	mainAnime     *Anime
	createdByUser *User
}

// Link returns the permalink for the track.
func (track *SoundTrack) Link() string {
	return "/tracks/" + track.ID
}

// Anime fetches all tagged anime of the sound track.
func (track *SoundTrack) Anime() []*Anime {
	var animeList []*Anime

	for _, tag := range track.Tags {
		if strings.HasPrefix(tag, "anime:") {
			animeID := strings.TrimPrefix(tag, "anime:")
			anime, err := GetAnime(animeID)

			if err != nil {
				color.Red("Error fetching anime: %v", err)
				continue
			}

			animeList = append(animeList, anime)
		}
	}

	return animeList
}

// MainAnime ...
func (track *SoundTrack) MainAnime() *Anime {
	if track.mainAnime != nil {
		return track.mainAnime
	}

	allAnime := track.Anime()

	if len(allAnime) == 0 {
		return nil
	}

	track.mainAnime = allAnime[0]
	return track.mainAnime
}

// CreatedByUser ...
func (track *SoundTrack) CreatedByUser() *User {
	if track.createdByUser != nil {
		return track.createdByUser
	}

	user, err := GetUser(track.CreatedBy)

	if err != nil {
		color.Red("Error fetching user: %v", err)
		return nil
	}

	track.createdByUser = user
	return track.createdByUser
}

// SortSoundTracksLatestFirst ...
func SortSoundTracksLatestFirst(tracks []*SoundTrack) {
	sort.Slice(tracks, func(i, j int) bool {
		return tracks[i].Created > tracks[j].Created
	})
}

// GetSoundTracksByUser ...
func GetSoundTracksByUser(user *User) ([]*SoundTrack, error) {
	var userTracks []*SoundTrack
	tracks, err := StreamSoundTracks()

	if err != nil {
		return nil, err
	}

	for track := range tracks {
		if track.CreatedBy == user.ID {
			userTracks = append(userTracks, track)
		}
	}

	return userTracks, nil
}

// StreamSoundTracks ...
func StreamSoundTracks() (chan *SoundTrack, error) {
	tracks, err := DB.All("SoundTrack")
	return tracks.(chan *SoundTrack), err
}

// AllSoundTracks ...
func AllSoundTracks() ([]*SoundTrack, error) {
	var all []*SoundTrack

	stream, err := StreamSoundTracks()

	if err != nil {
		return nil, err
	}

	for obj := range stream {
		all = append(all, obj)
	}

	return all, nil
}
<commit_msg>Added GetSoundTrack<commit_after>package arn

import (
	"sort"
	"strings"

	"github.com/fatih/color"
)

// SoundTrack ...
type SoundTrack struct {
	ID        string           `json:"id"`
	Media     []*ExternalMedia `json:"media"`
	Tags      []string         `json:"tags"`
	Likes     []string         `json:"likes"`
	Created   string           `json:"created"`
	CreatedBy string           `json:"createdBy"`
	Edited    string           `json:"edited"`

	mainAnime     *Anime
	createdByUser *User
}

// Link returns the permalink for the track.
func (track *SoundTrack) Link() string {
	return "/tracks/" + track.ID
}

// Anime fetches all tagged anime of the sound track.
func (track *SoundTrack) Anime() []*Anime {
	var animeList []*Anime

	for _, tag := range track.Tags {
		if strings.HasPrefix(tag, "anime:") {
			animeID := strings.TrimPrefix(tag, "anime:")
			anime, err := GetAnime(animeID)

			if err != nil {
				color.Red("Error fetching anime: %v", err)
				continue
			}

			animeList = append(animeList, anime)
		}
	}

	return animeList
}

// MainAnime ...
func (track *SoundTrack) MainAnime() *Anime {
	if track.mainAnime != nil {
		return track.mainAnime
	}

	allAnime := track.Anime()

	if len(allAnime) == 0 {
		return nil
	}

	track.mainAnime = allAnime[0]
	return track.mainAnime
}

// CreatedByUser ...
func (track *SoundTrack) CreatedByUser() *User {
	if track.createdByUser != nil {
		return track.createdByUser
	}

	user, err := GetUser(track.CreatedBy)

	if err != nil {
		color.Red("Error fetching user: %v", err)
		return nil
	}

	track.createdByUser = user
	return track.createdByUser
}

// SortSoundTracksLatestFirst ...
func SortSoundTracksLatestFirst(tracks []*SoundTrack) {
	sort.Slice(tracks, func(i, j int) bool {
		return tracks[i].Created > tracks[j].Created
	})
}

// GetSoundTrack ...
func GetSoundTrack(id string) (*SoundTrack, error) {
	track, err := DB.Get("SoundTrack", id)

	if err != nil {
		return nil, err
	}

	return track.(*SoundTrack), nil
}

// GetSoundTracksByUser ...
func GetSoundTracksByUser(user *User) ([]*SoundTrack, error) {
	var userTracks []*SoundTrack
	tracks, err := StreamSoundTracks()

	if err != nil {
		return nil, err
	}

	for track := range tracks {
		if track.CreatedBy == user.ID {
			userTracks = append(userTracks, track)
		}
	}

	return userTracks, nil
}

// StreamSoundTracks ...
func StreamSoundTracks() (chan *SoundTrack, error) {
	tracks, err := DB.All("SoundTrack")
	return tracks.(chan *SoundTrack), err
}

// AllSoundTracks ...
func AllSoundTracks() ([]*SoundTrack, error) {
	var all []*SoundTrack

	stream, err := StreamSoundTracks()

	if err != nil {
		return nil, err
	}

	for obj := range stream {
		all = append(all, obj)
	}

	return all, nil
}
<|endoftext|>


<commit_before>package oauth

import (
	"net/http"
	"testing"
)

func TestProviderIsAuthorizedGood(t *testing.T) {
	p := NewProvider(func(s string, h map[string]string) (*Consumer, error) {
		return NewConsumer(s, "consumersecret", ServiceProvider{}), nil
	})
	p.clock = &MockClock{Time: 1446226936}

	fakeRequest, err := http.NewRequest("GET", "https://example.com/some/path?q=query&q=another_query", nil)
	if err != nil {
		t.Fatal(err)
	}

	// Set header to good oauth1 header
	fakeRequest.Header.Set("Authorization", "OAuth oauth_nonce=\"799507437267152061446226936\", oauth_timestamp=\"1446226936\", oauth_version=\"1.0\", oauth_signature_method=\"HMAC-SHA1\", oauth_consumer_key=\"consumerkey\", oauth_signature=\"wNwcZEM4wZgCD5zvOA%2FYZ6Kl%2F8E%3D\"")

	authorized, err := p.IsAuthorized(fakeRequest)

	assertEq(t, err, nil)
	assertEq(t, *authorized, "consumerkey")
}
<commit_msg>test with equals in consumer key<commit_after>package oauth

import (
	"net/http"
	"testing"
)

func TestProviderIsAuthorizedGood(t *testing.T) {
	p := NewProvider(func(s string, h map[string]string) (*Consumer, error) {
		c := NewConsumer(s, "consumersecret", ServiceProvider{})
		c.signer = &MockSigner{}
		return c, nil
	})
	p.clock = &MockClock{Time: 1446226936}

	fakeRequest, err := http.NewRequest("GET", "https://example.com/some/path?q=query&q=another_query", nil)
	if err != nil {
		t.Fatal(err)
	}

	// Set header to good oauth1 header
	fakeRequest.Header.Set("Authorization", "OAuth oauth_nonce=\"799507437267152061446226936\", oauth_timestamp=\"1446226936\", oauth_version=\"1.0\", oauth_signature_method=\"HMAC-SHA1\", oauth_consumer_key=\"consumerkey\", oauth_signature=\"MOCK_SIGNATURE\"")

	authorized, err := p.IsAuthorized(fakeRequest)

	assertEq(t, err, nil)
	assertEq(t, *authorized, "consumerkey")
}

func TestConsumerKeyWithEqualsInIt(t *testing.T) {
	p := NewProvider(func(s string, h map[string]string) (*Consumer, error) {
		c := NewConsumer(s, "consumersecret", ServiceProvider{})
		c.signer = &MockSigner{}
		return c, nil
	})
	p.clock = &MockClock{Time: 1446226936}

	fakeRequest, err := http.NewRequest("GET", "https://example.com/some/path?q=query&q=another_query", nil)
	if err != nil {
		t.Fatal(err)
	}

	// Set header to good oauth1 header
	fakeRequest.Header.Set("Authorization", "OAuth oauth_nonce=\"799507437267152061446226936\", oauth_timestamp=\"1446226936\", oauth_version=\"1.0\", oauth_signature_method=\"HMAC-SHA1\", oauth_consumer_key=\"consumerkeywithequals=\", oauth_signature=\"MOCK_SIGNATURE\"")

	authorized, err := p.IsAuthorized(fakeRequest)

	assertEq(t, err, nil)
	assertEq(t, *authorized, "consumerkeywithequals=")
}
<|endoftext|>


<commit_before>package admin

import (
	"strings"

	"github.com/jinzhu/gorm"
	"github.com/qor/qor"
	"github.com/qor/qor-example/app/models"
	"github.com/qor/qor-example/config"
	"github.com/qor/qor-example/db"
	"github.com/qor/qor/admin"
	"github.com/qor/qor/resource"
	"github.com/qor/qor/transition"
	"github.com/qor/qor/utils"
	"github.com/qor/qor/validations"
)

var Admin *admin.Admin
var Countries = []string{"China", "Japan", "USA"}

func init() {
	Admin = admin.New(&qor.Config{DB: db.Publish.DraftDB()})
	Admin.SetSiteName("Qor DEMO")
	Admin.SetAuth(Auth{})

	// Add Dashboard
	Admin.AddMenu(&admin.Menu{Name: "Dashboard", Link: "/admin"})

	// Add Asset Manager, for rich editor
	assetManager := Admin.AddResource(&admin.AssetManager{}, &admin.Config{Invisible: true})

	// Add Product
	product := Admin.AddResource(&models.Product{}, &admin.Config{Menu: []string{"Product Management"}})
	product.Meta(&admin.Meta{Name: "MadeCountry", Type: "select_one", Collection: Countries})
	product.Meta(&admin.Meta{Name: "Description", Type: "rich_editor", Resource: assetManager})

	for _, country := range Countries {
		var country = country
		product.Scope(&admin.Scope{Name: country, Group: "Made Country", Handle: func(db *gorm.DB, ctx *qor.Context) *gorm.DB {
			return db.Where("made_country = ?", country)
		}})
	}

	product.IndexAttrs("-ColorVariations")

	Admin.AddResource(&models.Color{}, &admin.Config{Menu: []string{"Product Management"}})
	Admin.AddResource(&models.Size{}, &admin.Config{Menu: []string{"Product Management"}})
	Admin.AddResource(&models.Category{}, &admin.Config{Menu: []string{"Product Management"}})

	// Add Order
	order := Admin.AddResource(&models.Order{}, &admin.Config{Menu: []string{"Order Management"}})
	order.Meta(&admin.Meta{Name: "ShippingAddress", Type: "single_edit"})
	order.Meta(&admin.Meta{Name: "BillingAddress", Type: "single_edit"})

	// define scopes for Order
	for _, state := range []string{"checkout", "cancelled", "paid", "paid_cancelled", "processing", "shipped", "returned"} {
		var state = state
		order.Scope(&admin.Scope{
			Name:  state,
			Label: strings.Title(strings.Replace(state, "_", " ", -1)),
			Group: "Order Status",
			Handle: func(db *gorm.DB, context *qor.Context) *gorm.DB {
				return db.Where(models.Order{Transition: transition.Transition{State: state}})
			},
		})
	}
	order.IndexAttrs("-DiscountValue", "-OrderItems", "-AbandonedReason")
	order.NewAttrs("-DiscountValue", "-AbandonedReason")
	order.EditAttrs("-DiscountValue", "-AbandonedReason")
	order.ShowAttrs("-DiscountValue", "-AbandonedReason")

	// Define another resource for same model
	abandonedOrder := Admin.AddResource(&models.Order{}, &admin.Config{Name: "Abandoned Order", Menu: []string{"Order Management"}})
	abandonedOrder.Meta(&admin.Meta{Name: "ShippingAddress", Type: "single_edit"})
	abandonedOrder.Meta(&admin.Meta{Name: "BillingAddress", Type: "single_edit"})

	// Define default scope for abandoned orders
	abandonedOrder.Scope(&admin.Scope{
		Default: true,
		Handle: func(db *gorm.DB, context *qor.Context) *gorm.DB {
			return db.Where("abandoned_reason IS NOT NULL AND abandoned_reason <> ?", "")
		},
	})

	abandonedOrder.Scope(&admin.Scope{
		Name: "Amount Greater Than 10000",
		Handle: func(db *gorm.DB, context *qor.Context) *gorm.DB {
			return db.Where("payment_amount > ?", 10000)
		},
	})

	abandonedOrder.IndexAttrs("-DiscountValue", "-OrderItems")
	abandonedOrder.NewAttrs("-DiscountValue")
	abandonedOrder.EditAttrs("-DiscountValue")
	abandonedOrder.ShowAttrs("-DiscountValue")

	// Add Store
	store := Admin.AddResource(&models.Store{}, &admin.Config{Menu: []string{"Store Management"}})
	store.AddValidator(func(record interface{}, metaValues *resource.MetaValues, context *qor.Context) error {
		if meta := metaValues.Get("Name"); meta != nil {
			if name := utils.ToString(meta.Value); strings.TrimSpace(name) == "" {
				return validations.NewError(record, "Name", "Name can't be blank")
			}
		}
		return nil
	})

	// Add Translations
	Admin.AddResource(config.Config.I18n, &admin.Config{Menu: []string{"Site Management"}})

	// Add Newsletter
	newsletter := Admin.AddResource(&models.Newsletter{})
	newsletter.Meta(&admin.Meta{Name: "NewsletterType", Type: "select_one", Collection: []string{"Weekly", "Monthly", "Promotions"}})
	newsletter.Meta(&admin.Meta{Name: "MailType", Type: "select_one", Collection: []string{"HTML", "Text"}})

	// Add Setting
	Admin.AddResource(&models.Setting{}, &admin.Config{Singleton: true})

	// Add User
	user := Admin.AddResource(&models.User{})
	user.IndexAttrs("ID", "Email", "Name", "Gender", "Role")

	// Add Publish
	Admin.AddResource(db.Publish)
	initFuncMap()
}
<commit_msg>More scopes for Abandoned Orders<commit_after>package admin

import (
	"fmt"
	"strings"

	"github.com/jinzhu/gorm"
	"github.com/qor/qor"
	"github.com/qor/qor-example/app/models"
	"github.com/qor/qor-example/config"
	"github.com/qor/qor-example/db"
	"github.com/qor/qor/admin"
	"github.com/qor/qor/resource"
	"github.com/qor/qor/transition"
	"github.com/qor/qor/utils"
	"github.com/qor/qor/validations"
)

var Admin *admin.Admin
var Countries = []string{"China", "Japan", "USA"}

func init() {
	Admin = admin.New(&qor.Config{DB: db.Publish.DraftDB()})
	Admin.SetSiteName("Qor DEMO")
	Admin.SetAuth(Auth{})

	// Add Dashboard
	Admin.AddMenu(&admin.Menu{Name: "Dashboard", Link: "/admin"})

	// Add Asset Manager, for rich editor
	assetManager := Admin.AddResource(&admin.AssetManager{}, &admin.Config{Invisible: true})

	// Add Product
	product := Admin.AddResource(&models.Product{}, &admin.Config{Menu: []string{"Product Management"}})
	product.Meta(&admin.Meta{Name: "MadeCountry", Type: "select_one", Collection: Countries})
	product.Meta(&admin.Meta{Name: "Description", Type: "rich_editor", Resource: assetManager})

	for _, country := range Countries {
		var country = country
		product.Scope(&admin.Scope{Name: country, Group: "Made Country", Handle: func(db *gorm.DB, ctx *qor.Context) *gorm.DB {
			return db.Where("made_country = ?", country)
		}})
	}

	product.IndexAttrs("-ColorVariations")

	Admin.AddResource(&models.Color{}, &admin.Config{Menu: []string{"Product Management"}})
	Admin.AddResource(&models.Size{}, &admin.Config{Menu: []string{"Product Management"}})
	Admin.AddResource(&models.Category{}, &admin.Config{Menu: []string{"Product Management"}})

	// Add Order
	order := Admin.AddResource(&models.Order{}, &admin.Config{Menu: []string{"Order Management"}})
	order.Meta(&admin.Meta{Name: "ShippingAddress", Type: "single_edit"})
	order.Meta(&admin.Meta{Name: "BillingAddress", Type: "single_edit"})

	// define scopes for Order
	for _, state := range []string{"checkout", "cancelled", "paid", "paid_cancelled", "processing", "shipped", "returned"} {
		var state = state
		order.Scope(&admin.Scope{
			Name:  state,
			Label: strings.Title(strings.Replace(state, "_", " ", -1)),
			Group: "Order Status",
			Handle: func(db *gorm.DB, context *qor.Context) *gorm.DB {
				return db.Where(models.Order{Transition: transition.Transition{State: state}})
			},
		})
	}
	order.IndexAttrs("-DiscountValue", "-OrderItems", "-AbandonedReason")
	order.NewAttrs("-DiscountValue", "-AbandonedReason")
	order.EditAttrs("-DiscountValue", "-AbandonedReason")
	order.ShowAttrs("-DiscountValue", "-AbandonedReason")

	// Define another resource for same model
	abandonedOrder := Admin.AddResource(&models.Order{}, &admin.Config{Name: "Abandoned Order", Menu: []string{"Order Management"}})
	abandonedOrder.Meta(&admin.Meta{Name: "ShippingAddress", Type: "single_edit"})
	abandonedOrder.Meta(&admin.Meta{Name: "BillingAddress", Type: "single_edit"})

	// Define default scope for abandoned orders
	abandonedOrder.Scope(&admin.Scope{
		Default: true,
		Handle: func(db *gorm.DB, context *qor.Context) *gorm.DB {
			return db.Where("abandoned_reason IS NOT NULL AND abandoned_reason <> ?", "")
		},
	})

	// Define scopes for abandoned orders
	for _, amount := range []int{5000, 10000, 20000} {
		var amount = amount
		abandonedOrder.Scope(&admin.Scope{
			Name:  fmt.Sprint(amount),
			Group: "Amount Greater Than",
			Handle: func(db *gorm.DB, context *qor.Context) *gorm.DB {
				return db.Where("payment_amount > ?", amount)
			},
		})
	}

	abandonedOrder.IndexAttrs("-DiscountValue", "-OrderItems")
	abandonedOrder.NewAttrs("-DiscountValue")
	abandonedOrder.EditAttrs("-DiscountValue")
	abandonedOrder.ShowAttrs("-DiscountValue")

	// Add Store
	store := Admin.AddResource(&models.Store{}, &admin.Config{Menu: []string{"Store Management"}})
	store.AddValidator(func(record interface{}, metaValues *resource.MetaValues, context *qor.Context) error {
		if meta := metaValues.Get("Name"); meta != nil {
			if name := utils.ToString(meta.Value); strings.TrimSpace(name) == "" {
				return validations.NewError(record, "Name", "Name can't be blank")
			}
		}
		return nil
	})

	// Add Translations
	Admin.AddResource(config.Config.I18n, &admin.Config{Menu: []string{"Site Management"}})

	// Add Newsletter
	newsletter := Admin.AddResource(&models.Newsletter{})
	newsletter.Meta(&admin.Meta{Name: "NewsletterType", Type: "select_one", Collection: []string{"Weekly", "Monthly", "Promotions"}})
	newsletter.Meta(&admin.Meta{Name: "MailType", Type: "select_one", Collection: []string{"HTML", "Text"}})

	// Add Setting
	Admin.AddResource(&models.Setting{}, &admin.Config{Singleton: true})

	// Add User
	user := Admin.AddResource(&models.User{})
	user.IndexAttrs("ID", "Email", "Name", "Gender", "Role")

	// Add Publish
	Admin.AddResource(db.Publish)
	initFuncMap()
}
<|endoftext|>


<commit_before>package config

import (
	"fmt"
	"os"
	"time"

	"github.com/hashicorp/consul-template/signals"
)

// Bool returns a pointer to the given bool.
func Bool(b bool) *bool {
	return &b
}

// BoolVal returns the value of the boolean at the pointer, or false if the
// pointer is nil.
func BoolVal(b *bool) bool {
	if b == nil {
		return false
	}
	return *b
}

// BoolCopy returns a copy of the boolean pointer
func BoolCopy(b *bool) *bool {
	if b == nil {
		return nil
	}

	return Bool(*b)
}

// BoolGoString returns the value of the boolean for printing in a string.
func BoolGoString(b *bool) string {
	if b == nil {
		return "(*bool)(nil)"
	}
	return fmt.Sprintf("%t", *b)
}

// BoolPresent returns a boolean indicating if the pointer is nil, or if the
// pointer is pointing to the zero value..
func BoolPresent(b *bool) bool {
	if b == nil {
		return false
	}
	return true
}

// FileMode returns a pointer to the given os.FileMode.
func FileMode(o os.FileMode) *os.FileMode {
	return &o
}

// FileModeVal returns the value of the os.FileMode at the pointer, or 0 if the
// pointer is nil.
func FileModeVal(o *os.FileMode) os.FileMode {
	if o == nil {
		return 0
	}
	return *o
}

// FileModeCopy returns a copy of the os.FireMode
func FileModeCopy(o *os.FileMode) *os.FileMode {
	if o == nil {
		return nil
	}

	return FileMode(*o)
}

// FileModeGoString returns the value of the os.FileMode for printing in a
// string.
func FileModeGoString(o *os.FileMode) string {
	if o == nil {
		return "(*os.FileMode)(nil)"
	}
	return fmt.Sprintf("%q", *o)
}

// FileModePresent returns a boolean indicating if the pointer is nil, or if
// the pointer is pointing to the zero value.
func FileModePresent(o *os.FileMode) bool {
	if o == nil {
		return false
	}
	return *o != 0
}

// Int returns a pointer to the given int.
func Int(i int) *int {
	return &i
}

// IntVal returns the value of the int at the pointer, or 0 if the pointer is
// nil.
func IntVal(i *int) int {
	if i == nil {
		return 0
	}
	return *i
}

// IntCopy returns a copy of the int pointer
func IntCopy(i *int) *int {
	if i == nil {
		return nil
	}

	return Int(*i)
}

// IntGoString returns the value of the int for printing in a string.
func IntGoString(i *int) string {
	if i == nil {
		return "(*int)(nil)"
	}
	return fmt.Sprintf("%d", *i)
}

// IntPresent returns a boolean indicating if the pointer is nil, or if the
// pointer is pointing to the zero value.
func IntPresent(i *int) bool {
	if i == nil {
		return false
	}
	return *i != 0
}

// Uint returns a pointer to the given uint.
func Uint(i uint) *uint {
	return &i
}

// UintVal returns the value of the uint at the pointer, or 0 if the pointer is
// nil.
func UintVal(i *uint) uint {
	if i == nil {
		return 0
	}
	return *i
}

// UintCopy returns a copy of the uint pointer
func UintCopy(i *uint) *uint {
	if i == nil {
		return nil
	}

	return Uint(*i)
}

// UintGoString returns the value of the uint for printing in a string.
func UintGoString(i *uint) string {
	if i == nil {
		return "(*uint)(nil)"
	}
	return fmt.Sprintf("%d", *i)
}

// UintPresent returns a boolean indicating if the pointer is nil, or if the
// pointer is pointing to the zero value.
func UintPresent(i *uint) bool {
	if i == nil {
		return false
	}
	return *i != 0
}

// Signal returns a pointer to the given os.Signal.
func Signal(s os.Signal) *os.Signal {
	return &s
}

// SignalVal returns the value of the os.Signal at the pointer, or 0 if the
// pointer is nil.
func SignalVal(s *os.Signal) os.Signal {
	if s == nil {
		return (os.Signal)(nil)
	}
	return *s
}

// SignalCopy returns a copy of the os.Signal
func SignalCopy(s *os.Signal) *os.Signal {
	if s == nil {
		return nil
	}

	return Signal(*s)
}

// SignalGoString returns the value of the os.Signal for printing in a string.
func SignalGoString(s *os.Signal) string {
	if s == nil {
		return "(*os.Signal)(nil)"
	}
	if *s == nil {
		return "<nil>"
	}
	return fmt.Sprintf("%q", *s)
}

// SignalPresent returns a boolean indicating if the pointer is nil, or if the pointer is pointing to the zero value..
func SignalPresent(s *os.Signal) bool {
	if s == nil {
		return false
	}
	return *s != signals.SIGNIL
}

// String returns a pointer to the given string.
func String(s string) *string {
	return &s
}

// StringVal returns the value of the string at the pointer, or "" if the
// pointer is nil.
func StringVal(s *string) string {
	if s == nil {
		return ""
	}
	return *s
}

// StringCopy returns a copy of the string pointer
func StringCopy(s *string) *string {
	if s == nil {
		return nil
	}

	return String(*s)
}

// StringGoString returns the value of the string for printing in a string.
func StringGoString(s *string) string {
	if s == nil {
		return "(*string)(nil)"
	}
	return fmt.Sprintf("%q", *s)
}

// StringPresent returns a boolean indicating if the pointer is nil, or if the pointer is pointing to the zero value..
func StringPresent(s *string) bool {
	if s == nil {
		return false
	}
	return *s != ""
}

// TimeDuration returns a pointer to the given time.Duration.
func TimeDuration(t time.Duration) *time.Duration {
	return &t
}

// TimeDurationVal returns the value of the string at the pointer, or 0 if the
// pointer is nil.
func TimeDurationVal(t *time.Duration) time.Duration {
	if t == nil {
		return time.Duration(0)
	}
	return *t
}

// TimeDurationCopy returns a copy of the time.Duration pointer
func TimeDurationCopy(t *time.Duration) *time.Duration {
	if t == nil {
		return nil
	}

	return TimeDuration(*t)
}

// TimeDurationGoString returns the value of the time.Duration for printing in a
// string.
func TimeDurationGoString(t *time.Duration) string {
	if t == nil {
		return "(*time.Duration)(nil)"
	}
	return fmt.Sprintf("%s", t)
}

// TimeDurationPresent returns a boolean indicating if the pointer is nil, or if the pointer is pointing to the zero value..
func TimeDurationPresent(t *time.Duration) bool {
	if t == nil {
		return false
	}
	return *t != 0
}
<commit_msg>Remove unused helper functions<commit_after>package config

import (
	"fmt"
	"os"
	"time"

	"github.com/hashicorp/consul-template/signals"
)

// Bool returns a pointer to the given bool.
func Bool(b bool) *bool {
	return &b
}

// BoolVal returns the value of the boolean at the pointer, or false if the
// pointer is nil.
func BoolVal(b *bool) bool {
	if b == nil {
		return false
	}
	return *b
}

// BoolCopy returns a copy of the boolean pointer
func BoolCopy(b *bool) *bool {
	if b == nil {
		return nil
	}

	return Bool(*b)
}

// BoolGoString returns the value of the boolean for printing in a string.
func BoolGoString(b *bool) string {
	if b == nil {
		return "(*bool)(nil)"
	}
	return fmt.Sprintf("%t", *b)
}

// BoolPresent returns a boolean indicating if the pointer is nil, or if the
// pointer is pointing to the zero value..
func BoolPresent(b *bool) bool {
	if b == nil {
		return false
	}
	return true
}

// FileMode returns a pointer to the given os.FileMode.
func FileMode(o os.FileMode) *os.FileMode {
	return &o
}

// FileModeVal returns the value of the os.FileMode at the pointer, or 0 if the
// pointer is nil.
func FileModeVal(o *os.FileMode) os.FileMode {
	if o == nil {
		return 0
	}
	return *o
}

// FileModeGoString returns the value of the os.FileMode for printing in a
// string.
func FileModeGoString(o *os.FileMode) string {
	if o == nil {
		return "(*os.FileMode)(nil)"
	}
	return fmt.Sprintf("%q", *o)
}

// FileModePresent returns a boolean indicating if the pointer is nil, or if
// the pointer is pointing to the zero value.
func FileModePresent(o *os.FileMode) bool {
	if o == nil {
		return false
	}
	return *o != 0
}

// Int returns a pointer to the given int.
func Int(i int) *int {
	return &i
}

// IntVal returns the value of the int at the pointer, or 0 if the pointer is
// nil.
func IntVal(i *int) int {
	if i == nil {
		return 0
	}
	return *i
}

// IntGoString returns the value of the int for printing in a string.
func IntGoString(i *int) string {
	if i == nil {
		return "(*int)(nil)"
	}
	return fmt.Sprintf("%d", *i)
}

// IntPresent returns a boolean indicating if the pointer is nil, or if the
// pointer is pointing to the zero value.
func IntPresent(i *int) bool {
	if i == nil {
		return false
	}
	return *i != 0
}

// Uint returns a pointer to the given uint.
func Uint(i uint) *uint {
	return &i
}

// UintVal returns the value of the uint at the pointer, or 0 if the pointer is
// nil.
func UintVal(i *uint) uint {
	if i == nil {
		return 0
	}
	return *i
}

// UintCopy returns a copy of the uint pointer
func UintCopy(i *uint) *uint {
	if i == nil {
		return nil
	}

	return Uint(*i)
}

// UintGoString returns the value of the uint for printing in a string.
func UintGoString(i *uint) string {
	if i == nil {
		return "(*uint)(nil)"
	}
	return fmt.Sprintf("%d", *i)
}

// UintPresent returns a boolean indicating if the pointer is nil, or if the
// pointer is pointing to the zero value.
func UintPresent(i *uint) bool {
	if i == nil {
		return false
	}
	return *i != 0
}

// Signal returns a pointer to the given os.Signal.
func Signal(s os.Signal) *os.Signal {
	return &s
}

// SignalVal returns the value of the os.Signal at the pointer, or 0 if the
// pointer is nil.
func SignalVal(s *os.Signal) os.Signal {
	if s == nil {
		return (os.Signal)(nil)
	}
	return *s
}

// SignalGoString returns the value of the os.Signal for printing in a string.
func SignalGoString(s *os.Signal) string {
	if s == nil {
		return "(*os.Signal)(nil)"
	}
	if *s == nil {
		return "<nil>"
	}
	return fmt.Sprintf("%q", *s)
}

// SignalPresent returns a boolean indicating if the pointer is nil, or if the pointer is pointing to the zero value..
func SignalPresent(s *os.Signal) bool {
	if s == nil {
		return false
	}
	return *s != signals.SIGNIL
}

// String returns a pointer to the given string.
func String(s string) *string {
	return &s
}

// StringVal returns the value of the string at the pointer, or "" if the
// pointer is nil.
func StringVal(s *string) string {
	if s == nil {
		return ""
	}
	return *s
}

// StringCopy returns a copy of the string pointer
func StringCopy(s *string) *string {
	if s == nil {
		return nil
	}

	return String(*s)
}

// StringGoString returns the value of the string for printing in a string.
func StringGoString(s *string) string {
	if s == nil {
		return "(*string)(nil)"
	}
	return fmt.Sprintf("%q", *s)
}

// StringPresent returns a boolean indicating if the pointer is nil, or if the pointer is pointing to the zero value..
func StringPresent(s *string) bool {
	if s == nil {
		return false
	}
	return *s != ""
}

// TimeDuration returns a pointer to the given time.Duration.
func TimeDuration(t time.Duration) *time.Duration {
	return &t
}

// TimeDurationVal returns the value of the string at the pointer, or 0 if the
// pointer is nil.
func TimeDurationVal(t *time.Duration) time.Duration {
	if t == nil {
		return time.Duration(0)
	}
	return *t
}

// TimeDurationCopy returns a copy of the time.Duration pointer
func TimeDurationCopy(t *time.Duration) *time.Duration {
	if t == nil {
		return nil
	}

	return TimeDuration(*t)
}

// TimeDurationGoString returns the value of the time.Duration for printing in a
// string.
func TimeDurationGoString(t *time.Duration) string {
	if t == nil {
		return "(*time.Duration)(nil)"
	}
	return fmt.Sprintf("%s", t)
}

// TimeDurationPresent returns a boolean indicating if the pointer is nil, or if the pointer is pointing to the zero value..
func TimeDurationPresent(t *time.Duration) bool {
	if t == nil {
		return false
	}
	return *t != 0
}
<|endoftext|>


<commit_before>package distribution

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

	"github.com/docker/distribution/manifest/manifestlist"
	"github.com/docker/distribution/manifest/schema1"
	"github.com/docker/distribution/manifest/schema2"
	"github.com/docker/distribution/reference"
	"github.com/docker/docker/api/server/httputils"
	"github.com/docker/docker/api/types"
	registrytypes "github.com/docker/docker/api/types/registry"
	"github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/pkg/errors"
	"golang.org/x/net/context"
)

func (s *distributionRouter) getDistributionInfo(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
	if err := httputils.ParseForm(r); err != nil {
		return err
	}

	w.Header().Set("Content-Type", "application/json")

	var (
		config              = &types.AuthConfig{}
		authEncoded         = r.Header.Get("X-Registry-Auth")
		distributionInspect registrytypes.DistributionInspect
	)

	if authEncoded != "" {
		authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
		if err := json.NewDecoder(authJSON).Decode(&config); err != nil {
			// for a search it is not an error if no auth was given
			// to increase compatibility with the existing api it is defaulting to be empty
			config = &types.AuthConfig{}
		}
	}

	image := vars["name"]

	ref, err := reference.ParseAnyReference(image)
	if err != nil {
		return err
	}
	namedRef, ok := ref.(reference.Named)
	if !ok {
		if _, ok := ref.(reference.Digested); ok {
			// full image ID
			return errors.Errorf("no manifest found for full image ID")
		}
		return errors.Errorf("unknown image reference format: %s", image)
	}

	distrepo, _, err := s.backend.GetRepository(ctx, namedRef, config)
	if err != nil {
		return err
	}
	blobsrvc := distrepo.Blobs(ctx)

	if canonicalRef, ok := namedRef.(reference.Canonical); !ok {
		namedRef = reference.TagNameOnly(namedRef)

		taggedRef, ok := namedRef.(reference.NamedTagged)
		if !ok {
			return errors.Errorf("image reference not tagged: %s", image)
		}

		descriptor, err := distrepo.Tags(ctx).Get(ctx, taggedRef.Tag())
		if err != nil {
			return err
		}
		distributionInspect.Descriptor = v1.Descriptor{
			MediaType: descriptor.MediaType,
			Digest:    descriptor.Digest,
			Size:      descriptor.Size,
		}
	} else {
		// TODO(nishanttotla): Once manifests can be looked up as a blob, the
		// descriptor should be set using blobsrvc.Stat(ctx, canonicalRef.Digest())
		// instead of having to manually fill in the fields
		distributionInspect.Descriptor.Digest = canonicalRef.Digest()
	}

	// we have a digest, so we can retrieve the manifest
	mnfstsrvc, err := distrepo.Manifests(ctx)
	if err != nil {
		return err
	}
	mnfst, err := mnfstsrvc.Get(ctx, distributionInspect.Descriptor.Digest)
	if err != nil {
		return err
	}

	mediaType, payload, err := mnfst.Payload()
	if err != nil {
		return err
	}
	// update MediaType because registry might return something incorrect
	distributionInspect.Descriptor.MediaType = mediaType
	if distributionInspect.Descriptor.Size == 0 {
		distributionInspect.Descriptor.Size = int64(len(payload))
	}

	// retrieve platform information depending on the type of manifest
	switch mnfstObj := mnfst.(type) {
	case *manifestlist.DeserializedManifestList:
		for _, m := range mnfstObj.Manifests {
			distributionInspect.Platforms = append(distributionInspect.Platforms, v1.Platform{
				Architecture: m.Platform.Architecture,
				OS:           m.Platform.OS,
				OSVersion:    m.Platform.OSVersion,
				OSFeatures:   m.Platform.OSFeatures,
				Variant:      m.Platform.Variant,
			})
		}
	case *schema2.DeserializedManifest:
		configJSON, err := blobsrvc.Get(ctx, mnfstObj.Config.Digest)
		var platform v1.Platform
		if err == nil {
			err := json.Unmarshal(configJSON, &platform)
			if err == nil {
				distributionInspect.Platforms = append(distributionInspect.Platforms, platform)
			}
		}
	case *schema1.SignedManifest:
		platform := v1.Platform{
			Architecture: mnfstObj.Architecture,
			OS:           "linux",
		}
		distributionInspect.Platforms = append(distributionInspect.Platforms, platform)
	}

	return httputils.WriteJSON(w, http.StatusOK, distributionInspect)
}
<commit_msg>api: Only return a Platform when relevant information is available<commit_after>package distribution

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

	"github.com/docker/distribution/manifest/manifestlist"
	"github.com/docker/distribution/manifest/schema1"
	"github.com/docker/distribution/manifest/schema2"
	"github.com/docker/distribution/reference"
	"github.com/docker/docker/api/server/httputils"
	"github.com/docker/docker/api/types"
	registrytypes "github.com/docker/docker/api/types/registry"
	"github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/pkg/errors"
	"golang.org/x/net/context"
)

func (s *distributionRouter) getDistributionInfo(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
	if err := httputils.ParseForm(r); err != nil {
		return err
	}

	w.Header().Set("Content-Type", "application/json")

	var (
		config              = &types.AuthConfig{}
		authEncoded         = r.Header.Get("X-Registry-Auth")
		distributionInspect registrytypes.DistributionInspect
	)

	if authEncoded != "" {
		authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
		if err := json.NewDecoder(authJSON).Decode(&config); err != nil {
			// for a search it is not an error if no auth was given
			// to increase compatibility with the existing api it is defaulting to be empty
			config = &types.AuthConfig{}
		}
	}

	image := vars["name"]

	ref, err := reference.ParseAnyReference(image)
	if err != nil {
		return err
	}
	namedRef, ok := ref.(reference.Named)
	if !ok {
		if _, ok := ref.(reference.Digested); ok {
			// full image ID
			return errors.Errorf("no manifest found for full image ID")
		}
		return errors.Errorf("unknown image reference format: %s", image)
	}

	distrepo, _, err := s.backend.GetRepository(ctx, namedRef, config)
	if err != nil {
		return err
	}
	blobsrvc := distrepo.Blobs(ctx)

	if canonicalRef, ok := namedRef.(reference.Canonical); !ok {
		namedRef = reference.TagNameOnly(namedRef)

		taggedRef, ok := namedRef.(reference.NamedTagged)
		if !ok {
			return errors.Errorf("image reference not tagged: %s", image)
		}

		descriptor, err := distrepo.Tags(ctx).Get(ctx, taggedRef.Tag())
		if err != nil {
			return err
		}
		distributionInspect.Descriptor = v1.Descriptor{
			MediaType: descriptor.MediaType,
			Digest:    descriptor.Digest,
			Size:      descriptor.Size,
		}
	} else {
		// TODO(nishanttotla): Once manifests can be looked up as a blob, the
		// descriptor should be set using blobsrvc.Stat(ctx, canonicalRef.Digest())
		// instead of having to manually fill in the fields
		distributionInspect.Descriptor.Digest = canonicalRef.Digest()
	}

	// we have a digest, so we can retrieve the manifest
	mnfstsrvc, err := distrepo.Manifests(ctx)
	if err != nil {
		return err
	}
	mnfst, err := mnfstsrvc.Get(ctx, distributionInspect.Descriptor.Digest)
	if err != nil {
		return err
	}

	mediaType, payload, err := mnfst.Payload()
	if err != nil {
		return err
	}
	// update MediaType because registry might return something incorrect
	distributionInspect.Descriptor.MediaType = mediaType
	if distributionInspect.Descriptor.Size == 0 {
		distributionInspect.Descriptor.Size = int64(len(payload))
	}

	// retrieve platform information depending on the type of manifest
	switch mnfstObj := mnfst.(type) {
	case *manifestlist.DeserializedManifestList:
		for _, m := range mnfstObj.Manifests {
			distributionInspect.Platforms = append(distributionInspect.Platforms, v1.Platform{
				Architecture: m.Platform.Architecture,
				OS:           m.Platform.OS,
				OSVersion:    m.Platform.OSVersion,
				OSFeatures:   m.Platform.OSFeatures,
				Variant:      m.Platform.Variant,
			})
		}
	case *schema2.DeserializedManifest:
		configJSON, err := blobsrvc.Get(ctx, mnfstObj.Config.Digest)
		var platform v1.Platform
		if err == nil {
			err := json.Unmarshal(configJSON, &platform)
			if err == nil && (platform.OS != "" || platform.Architecture != "") {
				distributionInspect.Platforms = append(distributionInspect.Platforms, platform)
			}
		}
	case *schema1.SignedManifest:
		platform := v1.Platform{
			Architecture: mnfstObj.Architecture,
			OS:           "linux",
		}
		distributionInspect.Platforms = append(distributionInspect.Platforms, platform)
	}

	return httputils.WriteJSON(w, http.StatusOK, distributionInspect)
}
<|endoftext|>