<commit_before>package diff

import (
	"fmt"

	"github.com/spf13/cobra"

	"github.com/werf/kubedog/pkg/kube"
	"github.com/werf/logboek"

	"github.com/werf/werf/cmd/werf/common"
	"github.com/werf/werf/pkg/build"
	"github.com/werf/werf/pkg/container_runtime"
	"github.com/werf/werf/pkg/docker"
	"github.com/werf/werf/pkg/image"
	"github.com/werf/werf/pkg/ssh_agent"
	"github.com/werf/werf/pkg/storage/manager"
	"github.com/werf/werf/pkg/tmp_manager"
	"github.com/werf/werf/pkg/true_git"
	"github.com/werf/werf/pkg/werf"
)

var cmdData struct {
	PullUsername string
	PullPassword string
	Timeout      int
}

var commonCmdData common.CmdData

func NewCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "diff",
		Short: "Shows what changes will be performed by converge command",
		Long: common.GetLongCommandDescription(`Shows what new stages will be built, images published and during execution of converge command.

This command only shows what changes will be introduced by converge command and does not perform any changes.`),
		Example: `# Show changes that will be introduced by converge to build and deploy current application state into production environment
werf converge --stages-storage registry.mydomain.com/web/back/stages --images-repo registry.mydomain.com/web/back --env production`,
		DisableFlagsInUseLine: true,
		Annotations: map[string]string{
			common.CmdEnvAnno: common.EnvsDescription(common.WerfSecretKey),
		},
		RunE: func(cmd *cobra.Command, args []string) error {
			defer werf.PrintGlobalWarnings(common.BackgroundContext())

			if err := common.ProcessLogOptions(&commonCmdData); err != nil {
				common.PrintHelp(cmd)
				return err
			}

			common.LogVersion()

			return common.LogRunningTime(func() error {
				return runDiff()
			})
		},
	}

	common.SetupDir(&commonCmdData, cmd)
	common.SetupConfigPath(&commonCmdData, cmd)
	common.SetupConfigTemplatesDir(&commonCmdData, cmd)
	common.SetupTmpDir(&commonCmdData, cmd)
	common.SetupHomeDir(&commonCmdData, cmd)
	common.SetupSSHKey(&commonCmdData, cmd)

	common.SetupSecondaryStagesStorageOptions(&commonCmdData, cmd)
	common.SetupStagesStorageOptions(&commonCmdData, cmd)

	common.SetupDockerConfig(&commonCmdData, cmd, "Command needs granted permissions to read, pull and push images into the specified stages storage, to push images into the specified images repo, to pull base images")
	common.SetupInsecureRegistry(&commonCmdData, cmd)
	common.SetupSkipTlsVerifyRegistry(&commonCmdData, cmd)

	common.SetupLogOptions(&commonCmdData, cmd)
	common.SetupLogProjectDir(&commonCmdData, cmd)

	common.SetupSynchronization(&commonCmdData, cmd)

	common.SetupKubeConfig(&commonCmdData, cmd)
	common.SetupKubeConfigBase64(&commonCmdData, cmd)
	common.SetupKubeContext(&commonCmdData, cmd)
	common.SetupHelmChartDir(&commonCmdData, cmd)
	common.SetupStatusProgressPeriod(&commonCmdData, cmd)
	common.SetupHooksStatusProgressPeriod(&commonCmdData, cmd)
	common.SetupReleasesHistoryMax(&commonCmdData, cmd)

	common.SetupEnvironment(&commonCmdData, cmd)
	common.SetupRelease(&commonCmdData, cmd)
	common.SetupNamespace(&commonCmdData, cmd)
	common.SetupAddAnnotations(&commonCmdData, cmd)
	common.SetupAddLabels(&commonCmdData, cmd)

	common.SetupSet(&commonCmdData, cmd)
	common.SetupSetString(&commonCmdData, cmd)
	common.SetupValues(&commonCmdData, cmd)
	common.SetupSecretValues(&commonCmdData, cmd)
	common.SetupIgnoreSecretKey(&commonCmdData, cmd)

	common.SetupVirtualMerge(&commonCmdData, cmd)
	common.SetupVirtualMergeFromCommit(&commonCmdData, cmd)
	common.SetupVirtualMergeIntoCommit(&commonCmdData, cmd)

	common.SetupGitUnshallow(&commonCmdData, cmd)
	common.SetupAllowGitShallowClone(&commonCmdData, cmd)

	cmd.Flags().IntVarP(&cmdData.Timeout, "timeout", "t", 0, "Resources tracking timeout in seconds")

	return cmd
}

func runDiff() error {
	ctx := common.BackgroundContext()

	if err := werf.Init(*commonCmdData.TmpDir, *commonCmdData.HomeDir); err != nil {
		return fmt.Errorf("initialization error: %s", err)
	}

	if err := image.Init(); err != nil {
		return err
	}

	if err := true_git.Init(true_git.Options{LiveGitOutput: *commonCmdData.LogVerbose || *commonCmdData.LogDebug}); err != nil {
		return err
	}

	if err := common.DockerRegistryInit(&commonCmdData); err != nil {
		return err
	}

	if err := docker.Init(ctx, *commonCmdData.DockerConfig, *commonCmdData.LogVerbose, *commonCmdData.LogDebug); err != nil {
		return err
	}

	ctxWithDockerCli, err := docker.NewContext(ctx)
	if err != nil {
		return err
	}
	ctx = ctxWithDockerCli

	projectDir, err := common.GetProjectDir(&commonCmdData)
	if err != nil {
		return fmt.Errorf("getting project dir failed: %s", err)
	}

	common.ProcessLogProjectDir(&commonCmdData, projectDir)

	werfConfig, err := common.GetRequiredWerfConfig(ctx, projectDir, &commonCmdData, true)
	if err != nil {
		return fmt.Errorf("unable to load werf config: %s", err)
	}

	projectName := werfConfig.Meta.Project

	projectTmpDir, err := tmp_manager.CreateProjectDir(ctx)
	if err != nil {
		return fmt.Errorf("getting project tmp dir failed: %s", err)
	}
	defer tmp_manager.ReleaseProjectDir(projectTmpDir)

	containerRuntime := &container_runtime.LocalDockerServerRuntime{} // TODO

	stagesStorageAddress := common.GetOptionalStagesStorageAddress(&commonCmdData)
	stagesStorage, err := common.GetStagesStorage(stagesStorageAddress, containerRuntime, &commonCmdData)
	if err != nil {
		return err
	}

	synchronization, err := common.GetSynchronization(ctx, &commonCmdData, projectName, stagesStorage)
	if err != nil {
		return err
	}
	stagesStorageCache, err := common.GetStagesStorageCache(synchronization)
	if err != nil {
		return err
	}
	storageLockManager, err := common.GetStorageLockManager(ctx, synchronization)
	if err != nil {
		return err
	}
	secondaryStagesStorageList, err := common.GetSecondaryStagesStorageList(stagesStorage, containerRuntime, &commonCmdData)
	if err != nil {
		return err
	}

	storageManager := manager.NewStorageManager(projectName, stagesStorage, secondaryStagesStorageList, storageLockManager, stagesStorageCache)

	if err := ssh_agent.Init(ctx, *commonCmdData.SSHKeys); err != nil {
		return fmt.Errorf("cannot initialize ssh agent: %s", err)
	}
	defer func() {
		err := ssh_agent.Terminate()
		if err != nil {
			logboek.Warn().LogF("WARNING: ssh agent termination failed: %s\n", err)
		}
	}()

	if err := kube.Init(kube.InitOptions{kube.KubeConfigOptions{
		Context:          *commonCmdData.KubeContext,
		ConfigPath:       *commonCmdData.KubeConfig,
		ConfigDataBase64: *commonCmdData.KubeConfigBase64,
	}}); err != nil {
		return fmt.Errorf("cannot initialize kube: %s", err)
	}

	if err := common.InitKubedog(ctx); err != nil {
		return fmt.Errorf("cannot init kubedog: %s", err)
	}

	buildOptions, err := common.GetBuildOptions(&commonCmdData, werfConfig)
	if err != nil {
		return err
	}
	buildOptions.DryRun = true
	logboek.LogOptionalLn()

	conveyorWithRetry := build.NewConveyorWithRetryWrapper(werfConfig, nil, projectDir, projectTmpDir, ssh_agent.SSHAuthSock, containerRuntime, storageManager, storageLockManager, common.GetConveyorOptions(&commonCmdData))
	defer conveyorWithRetry.Terminate()

	var imagesInfoGetters []*image.InfoGetter
	if err := conveyorWithRetry.WithRetryBlock(ctx, func(c *build.Conveyor) error {
		if err := c.Build(ctx, buildOptions); err != nil {
			return err
		}

		imagesInfoGetters = c.GetImageInfoGetters()

		return nil
	}); err != nil {
		return err
	}

	logboek.LogOptionalLn()

	return fmt.Errorf("NOT IMPLEMENTED")
}
<commit_msg>Remove werf diff command<commit_after><|endoftext|>


<commit_before>package main

import (
	"fmt"
	"html/template"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"

	"github.com/gonuts/commander"
	"github.com/gonuts/flag"
	"github.com/gonuts/logger"
)

func lbpkr_make_cmd_self_bdist_rpm() *commander.Command {
	cmd := &commander.Command{
		Run:       lbpkr_run_cmd_self_bdist_rpm,
		UsageLine: "bdist-rpm [options]",
		Short:     "create a RPM package of lbpkr",
		Long: `
bdist-rpm creates a RPM package containing lbpkr.

ex:
 $ lbpkr self bdist-rpm
 $ lbpkr self bdist-rpm -name=lbpkr
 $ lbpkr self bdist-rpm -name=lbpkr -version=0.1.20140619
 $ lbpkr self bdist-rpm -name=lbpkr -version=0.1.20140619 -release=1
`,
		Flag: *flag.NewFlagSet("lbpkr-self-bdist-rpm", flag.ExitOnError),
	}
	cmd.Flag.Bool("v", false, "enable verbose mode")
	cmd.Flag.String("name", "lbpkr", "name of the RPM to generate")
	cmd.Flag.String("version", Version, "version of the RPM to generate")
	cmd.Flag.Int("release", 0, "release number of the RPM to generate")
	return cmd
}

func lbpkr_run_cmd_self_bdist_rpm(cmd *commander.Command, args []string) error {
	var err error

	debug := cmd.Flag.Lookup("v").Value.Get().(bool)
	name := cmd.Flag.Lookup("name").Value.Get().(string)
	vers := cmd.Flag.Lookup("version").Value.Get().(string)
	release := cmd.Flag.Lookup("release").Value.Get().(int)

	switch len(args) {
	case 0:
	default:
		cmd.Usage()
		return fmt.Errorf("lbpkr: invalid number of arguments. expected n=0. got=%d (%v)",
			len(args),
			args,
		)
	}

	tmpdir, err := ioutil.TempDir("", "lbpkr-self-bdist-rpm-")
	if err != nil {
		return err
	}
	defer os.RemoveAll(tmpdir)
	//fmt.Printf(">>> [%s]\n", tmpdir)

	rpmbuildroot := filepath.Join(tmpdir, "rpmbuild")

	// make sure there is no hysteresis effect from outside
	err = os.Setenv("MYSITEROOT", "")
	if err != nil {
		return fmt.Errorf("error resetting $MYSITEROOT: %v", err)
	}

	siteroot := ""
	cfg := NewConfig(siteroot)
	msg := logger.New("lbpkr")
	if debug {
		msg.SetLevel(logger.DEBUG)
	}

	rpmbuild, err := exec.LookPath("rpmbuild")
	if err != nil {
		msg.Errorf("could not locate 'rpmbuild': %v\n", err)
		return err
	}

	tarcmd := newCommand("lbpkr",
		"self", "bdist",
		"-name="+name,
		"-version="+vers,
		fmt.Sprintf("-v=%v", debug),
	)
	tarcmd.Stdout = os.Stdout
	tarcmd.Stderr = os.Stderr
	tarcmd.Stdin = os.Stdin
	err = tarcmd.Run()
	if err != nil {
		msg.Errorf("could not create tarball: %v\n", err)
		return err
	}

	data := struct {
		Url       string
		Prefix    string
		BuildRoot string
		Name      string
		Version   string
		Release   int
	}{
		Url:       "http://github.com/lhcb-org/lbpkr",
		Prefix:    cfg.Siteroot(),
		BuildRoot: tmpdir,
		Name:      name,
		Version:   vers,
		Release:   release,
	}

	rpm_arch := "x86_64"
	switch runtime.GOARCH {
	case "amd64":
		rpm_arch = "x86_64"
	case "386":
		rpm_arch = "i686"
	}

	rpm_fname := fmt.Sprintf("%s-%s-%d.%s.rpm", data.Name, data.Version, data.Release, rpm_arch)
	msg.Infof("creating [%s]...\n", rpm_fname)

	// prepare a tarball with the lbpkr binary.
	dirname := fmt.Sprintf("%s-%s", data.Name, data.Version)
	fname := dirname + ".tar.gz"
	bdist_fname := dirname + "." + rpm_arch + ".tar.gz"

	// create hierarchy of dirs for rpmbuild
	for _, dir := range []string{"RPMS", "SRPMS", "BUILD", "SOURCES", "SPECS", "tmp"} {
		err = os.MkdirAll(filepath.Join(rpmbuildroot, dir), 0755)
		if err != nil {
			return err
		}
	}

	// copy tarball
	err = bincp(filepath.Join(rpmbuildroot, "SOURCES", fname), bdist_fname)
	if err != nil {
		return err
	}

	// create spec-file
	spec_fname := fmt.Sprintf("%s-%s-%d.spec", data.Name, data.Version, data.Release)
	spec, err := os.Create(filepath.Join(
		rpmbuildroot, "SPECS",
		spec_fname,
	))
	if err != nil {
		return err
	}
	defer spec.Close()
	t := template.Must(template.New("bdist-rpm-spec").Parse(rpm_tmpl))
	err = t.Execute(spec, &data)
	if err != nil {
		return err
	}
	spec.Sync()
	spec.Close()

	rpm := newCommand(rpmbuild, "-ba", filepath.Join("SPECS", spec_fname))
	rpm.Dir = rpmbuildroot
	if debug {
		rpm.Stdout = os.Stdout
		rpm.Stderr = os.Stderr
	}

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

	err = bincp(rpm_fname, filepath.Join(rpmbuildroot, "RPMS", rpm_arch, rpm_fname))
	if err != nil {
		return err
	}

	msg.Infof("creating [%s]... [ok]\n", rpm_fname)
	return err
}

const rpm_tmpl = `
%define        __spec_install_post %{nil}
%define          debug_package %{nil}
%define        __os_install_post %{_dbpath}/brp-compress
%define _topdir   {{.BuildRoot}}/rpmbuild
%define _tmppath  %{_topdir}/tmp

Summary: lbpkr is a tool to install RPMs.
Name: {{.Name}}
Version: {{.Version}}
Release: {{.Release}}
License: BSD
Group: Science
SOURCE0 : %{name}-%{version}.tar.gz
URL: {{.Url}}
## disable automatic dependencies extraction
## FIXME(sbinet) remove when C-sqlite3 is not needed anymore.
AutoReqProv: no

BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root

%description
%{summary}

%prep
%setup -q

%build

%install
rm -rf %{buildroot}
mkdir -p  %{buildroot}/{{.Prefix}}
/bin/cp -r ./* %{buildroot}/{{.Prefix}}

%clean
rm -rf %{buildroot}

%files
%defattr(-,root,root,-)
/{{.Prefix}}/usr/bin/lbpkr
`
<commit_msg>bdist-rpm: display RPM content<commit_after>package main

import (
	"fmt"
	"html/template"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"

	"github.com/gonuts/commander"
	"github.com/gonuts/flag"
	"github.com/gonuts/logger"
)

func lbpkr_make_cmd_self_bdist_rpm() *commander.Command {
	cmd := &commander.Command{
		Run:       lbpkr_run_cmd_self_bdist_rpm,
		UsageLine: "bdist-rpm [options]",
		Short:     "create a RPM package of lbpkr",
		Long: `
bdist-rpm creates a RPM package containing lbpkr.

ex:
 $ lbpkr self bdist-rpm
 $ lbpkr self bdist-rpm -name=lbpkr
 $ lbpkr self bdist-rpm -name=lbpkr -version=0.1.20140619
 $ lbpkr self bdist-rpm -name=lbpkr -version=0.1.20140619 -release=1
`,
		Flag: *flag.NewFlagSet("lbpkr-self-bdist-rpm", flag.ExitOnError),
	}
	cmd.Flag.Bool("v", false, "enable verbose mode")
	cmd.Flag.String("name", "lbpkr", "name of the RPM to generate")
	cmd.Flag.String("version", Version, "version of the RPM to generate")
	cmd.Flag.Int("release", 0, "release number of the RPM to generate")
	return cmd
}

func lbpkr_run_cmd_self_bdist_rpm(cmd *commander.Command, args []string) error {
	var err error

	debug := cmd.Flag.Lookup("v").Value.Get().(bool)
	name := cmd.Flag.Lookup("name").Value.Get().(string)
	vers := cmd.Flag.Lookup("version").Value.Get().(string)
	release := cmd.Flag.Lookup("release").Value.Get().(int)

	switch len(args) {
	case 0:
	default:
		cmd.Usage()
		return fmt.Errorf("lbpkr: invalid number of arguments. expected n=0. got=%d (%v)",
			len(args),
			args,
		)
	}

	tmpdir, err := ioutil.TempDir("", "lbpkr-self-bdist-rpm-")
	if err != nil {
		return err
	}
	defer os.RemoveAll(tmpdir)
	//fmt.Printf(">>> [%s]\n", tmpdir)

	rpmbuildroot := filepath.Join(tmpdir, "rpmbuild")

	// make sure there is no hysteresis effect from outside
	err = os.Setenv("MYSITEROOT", "")
	if err != nil {
		return fmt.Errorf("error resetting $MYSITEROOT: %v", err)
	}

	siteroot := ""
	cfg := NewConfig(siteroot)
	msg := logger.New("lbpkr")
	if debug {
		msg.SetLevel(logger.DEBUG)
	}

	rpmbuild, err := exec.LookPath("rpmbuild")
	if err != nil {
		msg.Errorf("could not locate 'rpmbuild': %v\n", err)
		return err
	}

	tarcmd := newCommand("lbpkr",
		"self", "bdist",
		"-name="+name,
		"-version="+vers,
		fmt.Sprintf("-v=%v", debug),
	)
	tarcmd.Stdout = os.Stdout
	tarcmd.Stderr = os.Stderr
	tarcmd.Stdin = os.Stdin
	err = tarcmd.Run()
	if err != nil {
		msg.Errorf("could not create tarball: %v\n", err)
		return err
	}

	data := struct {
		Url       string
		Prefix    string
		BuildRoot string
		Name      string
		Version   string
		Release   int
	}{
		Url:       "http://github.com/lhcb-org/lbpkr",
		Prefix:    cfg.Siteroot(),
		BuildRoot: tmpdir,
		Name:      name,
		Version:   vers,
		Release:   release,
	}

	rpm_arch := "x86_64"
	switch runtime.GOARCH {
	case "amd64":
		rpm_arch = "x86_64"
	case "386":
		rpm_arch = "i686"
	}

	rpm_fname := fmt.Sprintf("%s-%s-%d.%s.rpm", data.Name, data.Version, data.Release, rpm_arch)
	msg.Infof("creating [%s]...\n", rpm_fname)

	// prepare a tarball with the lbpkr binary.
	dirname := fmt.Sprintf("%s-%s", data.Name, data.Version)
	fname := dirname + ".tar.gz"
	bdist_fname := dirname + "." + rpm_arch + ".tar.gz"

	// create hierarchy of dirs for rpmbuild
	for _, dir := range []string{"RPMS", "SRPMS", "BUILD", "SOURCES", "SPECS", "tmp"} {
		err = os.MkdirAll(filepath.Join(rpmbuildroot, dir), 0755)
		if err != nil {
			return err
		}
	}

	// copy tarball
	err = bincp(filepath.Join(rpmbuildroot, "SOURCES", fname), bdist_fname)
	if err != nil {
		return err
	}

	// create spec-file
	spec_fname := fmt.Sprintf("%s-%s-%d.spec", data.Name, data.Version, data.Release)
	spec, err := os.Create(filepath.Join(
		rpmbuildroot, "SPECS",
		spec_fname,
	))
	if err != nil {
		return err
	}
	defer spec.Close()
	t := template.Must(template.New("bdist-rpm-spec").Parse(rpm_tmpl))
	err = t.Execute(spec, &data)
	if err != nil {
		return err
	}
	spec.Sync()
	spec.Close()

	rpm := newCommand(rpmbuild, "-ba", filepath.Join("SPECS", spec_fname))
	rpm.Dir = rpmbuildroot
	if debug {
		rpm.Stdout = os.Stdout
		rpm.Stderr = os.Stderr
	}

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

	err = bincp(rpm_fname, filepath.Join(rpmbuildroot, "RPMS", rpm_arch, rpm_fname))
	if err != nil {
		return err
	}

	msg.Infof("creating [%s]... [ok]\n", rpm_fname)

	msg.Infof("content of [%s]:\n", rpm_fname)
	rpm = newCommand("rpm", "-q", "-filesbypkg", "-p", rpm_fname)
	rpm.Stdout = os.Stdout
	rpm.Stderr = os.Stderr
	err = rpm.Run()
	if err != nil {
		return err
	}

	return err
}

const rpm_tmpl = `
%define        __spec_install_post %{nil}
%define          debug_package %{nil}
%define        __os_install_post %{_dbpath}/brp-compress
%define _topdir   {{.BuildRoot}}/rpmbuild
%define _tmppath  %{_topdir}/tmp

Summary: lbpkr is a tool to install RPMs.
Name: {{.Name}}
Version: {{.Version}}
Release: {{.Release}}
License: BSD
Group: Science
SOURCE0 : %{name}-%{version}.tar.gz
URL: {{.Url}}
## disable automatic dependencies extraction
## FIXME(sbinet) remove when C-sqlite3 is not needed anymore.
AutoReqProv: no

BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root

%description
%{summary}

%prep
%setup -q

%build

%install
rm -rf %{buildroot}
mkdir -p  %{buildroot}/{{.Prefix}}
/bin/cp -r ./* %{buildroot}/{{.Prefix}}

%clean
rm -rf %{buildroot}

%files
%defattr(-,root,root,-)
/{{.Prefix}}/usr/bin/lbpkr
`
<|endoftext|>


<commit_before>/*
 *
 * 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 cmds

import (
	"fmt"

	"github.com/fabric8io/gofabric8/client"
	"github.com/fabric8io/gofabric8/util"
	"github.com/spf13/cobra"
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
)

type tenantDeleteFlags struct {
	cmd  *cobra.Command
	args []string

	confirm bool
	tenant  string
}

func NewCmdTenantDelete(f *cmdutil.Factory) *cobra.Command {
	p := &tenantDeleteFlags{}
	cmd := &cobra.Command{
		Use:   "delete",
		Short: "Deletes all your tenant resources",
		Run: func(cmd *cobra.Command, args []string) {
			p.cmd = cmd
			p.args = args
			if cmd.Flags().Lookup(yesFlag).Value.String() == "true" {
				p.confirm = true
			}
			handleError(p.tenantDelete(f))
		},
	}
	flags := cmd.Flags()
	flags.StringVarP(&p.tenant, "tenant", "t", "", "the name of the tenant to delete. If blank it will be discovered")
	return cmd
}

func (p *tenantDeleteFlags) tenantDelete(f *cmdutil.Factory) error {
	c, cfg := client.NewClient(f)
	ns, _, _ := f.DefaultNamespace()
	oc, _ := client.NewOpenShiftClient(cfg)
	initSchema()

	var err error
	userNS := p.tenant
	if len(userNS) == 0 {
		userNS, err = detectCurrentUserNamespace(ns, c, oc)
		if err != nil {
			return err
		}
	}
	if !p.confirm {
		confirm := ""
		util.Warn("WARNING this command will delete all of your tenant resource, pipelines, jobs, and apps\n")
		util.Info("for your tenant: ")
		util.Successf("%s", userNS)
		util.Warn("\nContinue [y/N]: ")
		fmt.Scanln(&confirm)
		if confirm != "y" {
			util.Warn("Aborted\n")
			return nil
		}
	}

	util.Info("Deleting tenant: ")
	util.Successf("%s\n\n", userNS)

	ocCLI := "oc"
	stageNS := fmt.Sprintf("%s-stage", userNS)
	runNS := fmt.Sprintf("%s-run", userNS)
	cheNS := fmt.Sprintf("%s-che", userNS)
	jenkinsNS := fmt.Sprintf("%s-jenkins", userNS)

	// zap jenkins resources
	util.Infof("Removing jenkins namespace resources in %s\n", jenkinsNS)
	err = runCommand(ocCLI, "delete", "all", "--all", "-n", jenkinsNS, "--cascade=true", "--grace-period=-50")
	if err != nil {
		return nil
	}
	err = runCommand(ocCLI, "delete", "pvc", "--all", "-n", jenkinsNS, "--cascade=true", "--grace-period=-50")
	if err != nil {
		return nil
	}

	// zap other projects
	projectsToRemove := []string{stageNS, runNS, cheNS, userNS}
	for _, ns := range projectsToRemove {
		util.Infof("Removing project %s\n", ns)
		err = runCommand(ocCLI, "delete", "project", ns, "--cascade=true", "--grace-period=-50")
		if err != nil {
			return nil
		}
	}
	util.Infof("Tenant %s now deleted.\n", userNS)
	util.Infof("Now please Update your Tenant via: https://github.com/openshiftio/openshift.io/wiki/FAQ#how-do-i-update-my-tenant-\n\n")
	return nil
}
<commit_msg>lets remove more resources from the jenkins namespace<commit_after>/*
 *
 * 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 cmds

import (
	"fmt"

	"github.com/fabric8io/gofabric8/client"
	"github.com/fabric8io/gofabric8/util"
	"github.com/spf13/cobra"
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
)

type tenantDeleteFlags struct {
	cmd  *cobra.Command
	args []string

	confirm bool
	tenant  string
}

func NewCmdTenantDelete(f *cmdutil.Factory) *cobra.Command {
	p := &tenantDeleteFlags{}
	cmd := &cobra.Command{
		Use:   "delete",
		Short: "Deletes all your tenant resources",
		Run: func(cmd *cobra.Command, args []string) {
			p.cmd = cmd
			p.args = args
			if cmd.Flags().Lookup(yesFlag).Value.String() == "true" {
				p.confirm = true
			}
			handleError(p.tenantDelete(f))
		},
	}
	flags := cmd.Flags()
	flags.StringVarP(&p.tenant, "tenant", "t", "", "the name of the tenant to delete. If blank it will be discovered")
	return cmd
}

func (p *tenantDeleteFlags) tenantDelete(f *cmdutil.Factory) error {
	c, cfg := client.NewClient(f)
	ns, _, _ := f.DefaultNamespace()
	oc, _ := client.NewOpenShiftClient(cfg)
	initSchema()

	var err error
	userNS := p.tenant
	if len(userNS) == 0 {
		userNS, err = detectCurrentUserNamespace(ns, c, oc)
		if err != nil {
			return err
		}
	}
	if !p.confirm {
		confirm := ""
		util.Warn("WARNING this command will delete all of your tenant resource, pipelines, jobs, and apps\n")
		util.Info("for your tenant: ")
		util.Successf("%s", userNS)
		util.Warn("\nContinue [y/N]: ")
		fmt.Scanln(&confirm)
		if confirm != "y" {
			util.Warn("Aborted\n")
			return nil
		}
	}

	util.Info("Deleting tenant: ")
	util.Successf("%s\n\n", userNS)

	ocCLI := "oc"
	stageNS := fmt.Sprintf("%s-stage", userNS)
	runNS := fmt.Sprintf("%s-run", userNS)
	cheNS := fmt.Sprintf("%s-che", userNS)
	jenkinsNS := fmt.Sprintf("%s-jenkins", userNS)

	// zap jenkins resources
	util.Infof("Removing jenkins namespace resources in %s\n", jenkinsNS)
	err = runCommand(ocCLI, "delete", "all", "--all", "-n", jenkinsNS, "--cascade=true", "--grace-period=-50")
	if err != nil {
		return nil
	}
	err = runCommand(ocCLI, "delete", "pvc", "--all", "-n", jenkinsNS, "--cascade=true", "--grace-period=-50")
	if err != nil {
		return nil
	}
	err = runCommand(ocCLI, "delete", "cm", "--all", "-n", jenkinsNS, "--cascade=true", "--grace-period=-50")
	if err != nil {
		return nil
	}
	err = runCommand(ocCLI, "delete", "sa", "--all", "-n", jenkinsNS, "--cascade=true", "--grace-period=-50")
	if err != nil {
		return nil
	}
	err = runCommand(ocCLI, "delete", "secret", "--all", "-n", jenkinsNS, "--cascade=true", "--grace-period=-50")
	if err != nil {
		return nil
	}

	// zap other projects
	projectsToRemove := []string{stageNS, runNS, cheNS, userNS}
	for _, ns := range projectsToRemove {
		util.Infof("Removing project %s\n", ns)
		err = runCommand(ocCLI, "delete", "project", ns, "--cascade=true", "--grace-period=-50")
		if err != nil {
			return nil
		}
	}
	util.Infof("Tenant %s now deleted.\n", userNS)
	util.Infof("Now please Update your Tenant via: https://github.com/openshiftio/openshift.io/wiki/FAQ#how-do-i-update-my-tenant-\n\n")
	return nil
}
<|endoftext|>


<commit_before>package config

import (
	"encoding/json"

	"github.com/gruntwork-io/terragrunt/errors"
	"github.com/gruntwork-io/terragrunt/options"
	"github.com/zclconf/go-cty/cty"
	"github.com/zclconf/go-cty/cty/function"
	"github.com/zclconf/go-cty/cty/gocty"
	ctyjson "github.com/zclconf/go-cty/cty/json"
)

// Create a cty Function that takes as input parameters a slice of strings (var args, so this slice could be of any
// length) and returns as output a string. The implementation of the function calls the given toWrap function, passing
// it the input parameters string slice as well as the given include and terragruntOptions.
func wrapStringSliceToStringAsFuncImpl(toWrap func(params []string, include *IncludeConfig, terragruntOptions *options.TerragruntOptions) (string, error), include *IncludeConfig, terragruntOptions *options.TerragruntOptions) function.Function {
	return function.New(&function.Spec{
		VarParam: &function.Parameter{Type: cty.String},
		Type:     function.StaticReturnType(cty.String),
		Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
			params, err := ctySliceToStringSlice(args)
			if err != nil {
				return cty.StringVal(""), err
			}
			out, err := toWrap(params, include, terragruntOptions)
			if err != nil {
				return cty.StringVal(""), err
			}
			return cty.StringVal(out), nil
		},
	})
}

// Create a cty Function that takes no input parameters and returns as output a string. The implementation of the
// function calls the given toWrap function, passing it the given include and terragruntOptions.
func wrapVoidToStringAsFuncImpl(toWrap func(include *IncludeConfig, terragruntOptions *options.TerragruntOptions) (string, error), include *IncludeConfig, terragruntOptions *options.TerragruntOptions) function.Function {
	return function.New(&function.Spec{
		Type: function.StaticReturnType(cty.String),
		Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
			out, err := toWrap(include, terragruntOptions)
			if err != nil {
				return cty.StringVal(""), err
			}
			return cty.StringVal(out), nil
		},
	})
}

// Create a cty Function that takes no input parameters and returns as output a string slice. The implementation of the
// function returns the given string slice.
func wrapStaticValueToStringSliceAsFuncImpl(out []string) function.Function {
	return function.New(&function.Spec{
		Type: function.StaticReturnType(cty.List(cty.String)),
		Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
			outVals := []cty.Value{}
			for _, val := range out {
				outVals = append(outVals, cty.StringVal(val))
			}
			return cty.ListVal(outVals), nil
		},
	})
}

// Create a cty Function that takes as input parameters a slice of strings (var args, so this slice could be of any
// length) and returns as output a dynamic value. The implementation of the function calls the given toWrap function, passing
// it the input parameters string slice as well as the given include and terragruntOptions.
func wrapStringSliceToDynamicValueAsFuncImpl(
	toWrap func(params []string, include *IncludeConfig, terragruntOptions *options.TerragruntOptions) (cty.Value, error),
	include *IncludeConfig,
	terragruntOptions *options.TerragruntOptions,
) function.Function {
	return function.New(&function.Spec{
		VarParam: &function.Parameter{Type: cty.String},
		Type:     function.StaticReturnType(cty.DynamicPseudoType),
		Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
			params, err := ctySliceToStringSlice(args)
			if err != nil {
				return cty.NilVal, err
			}
			return toWrap(params, include, terragruntOptions)
		},
	})
}

// Convert the slice of cty values to a slice of strings. If any of the values in the given slice is not a string,
// return an error.
func ctySliceToStringSlice(args []cty.Value) ([]string, error) {
	var out []string
	for _, arg := range args {
		if arg.Type() != cty.String {
			return nil, errors.WithStackTrace(InvalidParameterType{Expected: "string", Actual: arg.Type().FriendlyName()})
		}
		out = append(out, arg.AsString())
	}
	return out, nil
}

// This is a hacky workaround to convert a cty Value to a Go map[string]interface{}. cty does not support this directly
// (https://github.com/hashicorp/hcl2/issues/108) and doing it with gocty.FromCtyValue is nearly impossible, as cty
// requires you to specify all the output types and will error out when it hits interface{}. So, as an ugly workaround,
// we convert the given value to JSON using cty's JSON library and then convert the JSON back to a
// map[string]interface{} using the Go json library.
func parseCtyValueToMap(value cty.Value) (map[string]interface{}, error) {
	jsonBytes, err := ctyjson.Marshal(value, cty.DynamicPseudoType)
	if err != nil {
		return nil, errors.WithStackTrace(err)
	}

	var ctyJsonOutput CtyJsonOutput
	if err := json.Unmarshal(jsonBytes, &ctyJsonOutput); err != nil {
		return nil, errors.WithStackTrace(err)
	}

	return ctyJsonOutput.Value, nil
}

// When you convert a cty value to JSON, if any of that types are not yet known (i.e., are labeled as
// DynamicPseudoType), cty's Marshall method will write the type information to a type field and the actual value to
// a value field. This struct is used to capture that information so when we parse the JSON back into a Go struct, we
// can pull out just the Value field we need.
type CtyJsonOutput struct {
	Value map[string]interface{}
	Type  interface{}
}

// convertValuesMapToCtyVal takes a map of name - cty.Value pairs and converts to a single cty.Value object.
func convertValuesMapToCtyVal(valMap map[string]cty.Value) (cty.Value, error) {
	valMapAsCty := cty.NilVal
	if valMap != nil && len(valMap) > 0 {
		var err error
		valMapAsCty, err = gocty.ToCtyValue(valMap, generateTypeFromValuesMap(valMap))
		if err != nil {
			return valMapAsCty, errors.WithStackTrace(err)
		}
	}
	return valMapAsCty, nil
}

// generateTypeFromValuesMap takes a values map and returns an object type that has the same number of fields, but
// bound to each type of the underlying evaluated expression. This is the only way the HCL decoder will be happy, as
// object type is the only map type that allows different types for each attribute (cty.Map requires all attributes to
// have the same type.
func generateTypeFromValuesMap(valMap map[string]cty.Value) cty.Type {
	outType := map[string]cty.Type{}
	for k, v := range valMap {
		outType[k] = v.Type()
	}
	return cty.Object(outType)
}
<commit_msg>Remove unnecessary func<commit_after>package config

import (
	"encoding/json"

	"github.com/gruntwork-io/terragrunt/errors"
	"github.com/gruntwork-io/terragrunt/options"
	"github.com/zclconf/go-cty/cty"
	"github.com/zclconf/go-cty/cty/function"
	"github.com/zclconf/go-cty/cty/gocty"
	ctyjson "github.com/zclconf/go-cty/cty/json"
)

// Create a cty Function that takes as input parameters a slice of strings (var args, so this slice could be of any
// length) and returns as output a string. The implementation of the function calls the given toWrap function, passing
// it the input parameters string slice as well as the given include and terragruntOptions.
func wrapStringSliceToStringAsFuncImpl(toWrap func(params []string, include *IncludeConfig, terragruntOptions *options.TerragruntOptions) (string, error), include *IncludeConfig, terragruntOptions *options.TerragruntOptions) function.Function {
	return function.New(&function.Spec{
		VarParam: &function.Parameter{Type: cty.String},
		Type:     function.StaticReturnType(cty.String),
		Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
			params, err := ctySliceToStringSlice(args)
			if err != nil {
				return cty.StringVal(""), err
			}
			out, err := toWrap(params, include, terragruntOptions)
			if err != nil {
				return cty.StringVal(""), err
			}
			return cty.StringVal(out), nil
		},
	})
}

// Create a cty Function that takes no input parameters and returns as output a string. The implementation of the
// function calls the given toWrap function, passing it the given include and terragruntOptions.
func wrapVoidToStringAsFuncImpl(toWrap func(include *IncludeConfig, terragruntOptions *options.TerragruntOptions) (string, error), include *IncludeConfig, terragruntOptions *options.TerragruntOptions) function.Function {
	return function.New(&function.Spec{
		Type: function.StaticReturnType(cty.String),
		Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
			out, err := toWrap(include, terragruntOptions)
			if err != nil {
				return cty.StringVal(""), err
			}
			return cty.StringVal(out), nil
		},
	})
}

// Create a cty Function that takes no input parameters and returns as output a string slice. The implementation of the
// function returns the given string slice.
func wrapStaticValueToStringSliceAsFuncImpl(out []string) function.Function {
	return function.New(&function.Spec{
		Type: function.StaticReturnType(cty.List(cty.String)),
		Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
			outVals := []cty.Value{}
			for _, val := range out {
				outVals = append(outVals, cty.StringVal(val))
			}
			return cty.ListVal(outVals), nil
		},
	})
}

// Convert the slice of cty values to a slice of strings. If any of the values in the given slice is not a string,
// return an error.
func ctySliceToStringSlice(args []cty.Value) ([]string, error) {
	var out []string
	for _, arg := range args {
		if arg.Type() != cty.String {
			return nil, errors.WithStackTrace(InvalidParameterType{Expected: "string", Actual: arg.Type().FriendlyName()})
		}
		out = append(out, arg.AsString())
	}
	return out, nil
}

// This is a hacky workaround to convert a cty Value to a Go map[string]interface{}. cty does not support this directly
// (https://github.com/hashicorp/hcl2/issues/108) and doing it with gocty.FromCtyValue is nearly impossible, as cty
// requires you to specify all the output types and will error out when it hits interface{}. So, as an ugly workaround,
// we convert the given value to JSON using cty's JSON library and then convert the JSON back to a
// map[string]interface{} using the Go json library.
func parseCtyValueToMap(value cty.Value) (map[string]interface{}, error) {
	jsonBytes, err := ctyjson.Marshal(value, cty.DynamicPseudoType)
	if err != nil {
		return nil, errors.WithStackTrace(err)
	}

	var ctyJsonOutput CtyJsonOutput
	if err := json.Unmarshal(jsonBytes, &ctyJsonOutput); err != nil {
		return nil, errors.WithStackTrace(err)
	}

	return ctyJsonOutput.Value, nil
}

// When you convert a cty value to JSON, if any of that types are not yet known (i.e., are labeled as
// DynamicPseudoType), cty's Marshall method will write the type information to a type field and the actual value to
// a value field. This struct is used to capture that information so when we parse the JSON back into a Go struct, we
// can pull out just the Value field we need.
type CtyJsonOutput struct {
	Value map[string]interface{}
	Type  interface{}
}

// convertValuesMapToCtyVal takes a map of name - cty.Value pairs and converts to a single cty.Value object.
func convertValuesMapToCtyVal(valMap map[string]cty.Value) (cty.Value, error) {
	valMapAsCty := cty.NilVal
	if valMap != nil && len(valMap) > 0 {
		var err error
		valMapAsCty, err = gocty.ToCtyValue(valMap, generateTypeFromValuesMap(valMap))
		if err != nil {
			return valMapAsCty, errors.WithStackTrace(err)
		}
	}
	return valMapAsCty, nil
}

// generateTypeFromValuesMap takes a values map and returns an object type that has the same number of fields, but
// bound to each type of the underlying evaluated expression. This is the only way the HCL decoder will be happy, as
// object type is the only map type that allows different types for each attribute (cty.Map requires all attributes to
// have the same type.
func generateTypeFromValuesMap(valMap map[string]cty.Value) cty.Type {
	outType := map[string]cty.Type{}
	for k, v := range valMap {
		outType[k] = v.Type()
	}
	return cty.Object(outType)
}
<|endoftext|>


<commit_before>// Copyright (C) 2017 Michał Matczuk
// Use of this source code is governed by an AGPL-style
// license that can be found in the LICENSE file.

package id

import (
	"bytes"
	"crypto/sha256"
	"crypto/subtle"
	"encoding/base32"
	"errors"
	"fmt"
	"regexp"
	"strings"

	"github.com/calmh/luhn"
)

// ID is the type representing a generated ID.
type ID [32]byte

// New generates a new ID from the given input bytes.
func New(data []byte) ID {
	var id ID

	hasher := sha256.New()
	hasher.Write(data)
	hasher.Sum(id[:0])

	return id
}

// NewFromString creates a new ID from the given string.
func NewFromString(s string) ID {
	return New([]byte(s))
}

// NewFromBytes creates a new ID with the value of the given byte slice.  The
// given byte slice must be 32 bytes long (the same length as ID), or this
// function will panic.
func NewFromBytes(b []byte) ID {
	var id ID

	if len(b) != len(id) {
		panic("invalid slice length for id")
	}

	copy(id[0:], b)
	return id
}

// String returns the canonical representation of the ID.
func (i ID) String() string {
	ss := base32.StdEncoding.EncodeToString(i[:])
	ss = strings.Trim(ss, "=")

	// Add a Luhn check 'digit' for the ID.
	ss, err := luhnify(ss)
	if err != nil {
		// Should never happen
		panic(err)
	}

	// Return the given ID as chunks.
	ss = chunkify(ss)

	return ss
}

// Compares the two given IDs.  Note that this function is NOT SAFE AGAINST
// TIMING ATTACKS.  If you are simply checking for equality, please use the
// Equals function, which is.
func (i ID) Compare(other ID) int {
	return bytes.Compare(i[:], other[:])
}

// Checks the two given IDs for equality.  This function uses a constant-time
// comparison algorithm to prevent timing attacks.
func (i ID) Equals(other ID) bool {
	return subtle.ConstantTimeCompare(i[:], other[:]) == 1
}

// Implements the `TextMarshaler` interface from the encoding package.
func (i *ID) MarshalText() ([]byte, error) {
	return []byte(i.String()), nil
}

// Implements the `TextUnmarshaler` interface from the encoding package.
func (i *ID) UnmarshalText(bs []byte) (err error) {
	// Convert to the canonical encoding - uppercase, no '=', no chunks, and
	// with any potential typos fixed.
	id := string(bs)
	id = strings.Trim(id, "=")
	id = strings.ToUpper(id)
	id = untypeoify(id)
	id = unchunkify(id)

	if len(id) != 56 {
		return errors.New("device ID invalid: incorrect length")
	}

	// Remove & verify Luhn check digits
	id, err = unluhnify(id)
	if err != nil {
		return err
	}

	// Base32 decode
	dec, err := base32.StdEncoding.DecodeString(id + "====")
	if err != nil {
		return err
	}

	// Done!
	copy(i[:], dec)
	return nil
}

// Add Luhn check digits to a string, returning the new one.
func luhnify(s string) (string, error) {
	if len(s) != 52 {
		panic("unsupported string length")
	}

	// Split the string into chunks of length 13, and add a Luhn check digit to
	// each one.
	res := make([]string, 0, 4)
	for i := 0; i < 4; i++ {
		chunk := s[i*13 : (i+1)*13]

		l, err := luhn.Base32.Generate(chunk)
		if err != nil {
			return "", err
		}

		res = append(res, fmt.Sprintf("%s%c", chunk, l))
	}

	return res[0] + res[1] + res[2] + res[3], nil
}

// Remove Luhn check digits from the given string, validating that they are
// correct.
func unluhnify(s string) (string, error) {
	if len(s) != 56 {
		return "", fmt.Errorf("unsupported string length %d", len(s))
	}

	res := make([]string, 0, 4)
	for i := 0; i < 4; i++ {
		// 13 characters, plus the Luhn digit.
		chunk := s[i*14 : (i+1)*14]

		// Get the expected check digit.
		l, err := luhn.Base32.Generate(chunk[0:13])
		if err != nil {
			return "", err
		}

		// Validate the digits match.
		if fmt.Sprintf("%c", l) != chunk[13:] {
			return "", errors.New("check digit incorrect")
		}

		res = append(res, chunk[0:13])
	}

	return res[0] + res[1] + res[2] + res[3], nil
}

// Returns a string split into chunks of size 7.
func chunkify(s string) string {
	s = regexp.MustCompile("(.{7})").ReplaceAllString(s, "$1-")
	s = strings.Trim(s, "-")
	return s
}

// Un-chunks a string by removing all hyphens and spaces.
func unchunkify(s string) string {
	s = strings.Replace(s, "-", "", -1)
	s = strings.Replace(s, " ", "", -1)
	return s
}

// We use base32 encoding, which uses 26 characters, and then the numbers
// 234567.  This is useful since the alphabet doesn't contain the numbers 0, 1,
// or 8, which means we can replace them with their letter-lookalikes.
func untypeoify(s string) string {
	s = strings.Replace(s, "0", "O", -1)
	s = strings.Replace(s, "1", "I", -1)
	s = strings.Replace(s, "8", "B", -1)
	return s
}
<commit_msg>id: removal of unused constructors<commit_after>// Copyright (C) 2017 Michał Matczuk
// Use of this source code is governed by an AGPL-style
// license that can be found in the LICENSE file.

package id

import (
	"bytes"
	"crypto/sha256"
	"crypto/subtle"
	"encoding/base32"
	"errors"
	"fmt"
	"regexp"
	"strings"

	"github.com/calmh/luhn"
)

// ID is the type representing a generated ID.
type ID [32]byte

// New generates a new ID from the given input bytes.
func New(data []byte) ID {
	var id ID

	hasher := sha256.New()
	hasher.Write(data)
	hasher.Sum(id[:0])

	return id
}

// String returns the canonical representation of the ID.
func (i ID) String() string {
	ss := base32.StdEncoding.EncodeToString(i[:])
	ss = strings.Trim(ss, "=")

	// Add a Luhn check 'digit' for the ID.
	ss, err := luhnify(ss)
	if err != nil {
		// Should never happen
		panic(err)
	}

	// Return the given ID as chunks.
	ss = chunkify(ss)

	return ss
}

// Compares the two given IDs.  Note that this function is NOT SAFE AGAINST
// TIMING ATTACKS.  If you are simply checking for equality, please use the
// Equals function, which is.
func (i ID) Compare(other ID) int {
	return bytes.Compare(i[:], other[:])
}

// Checks the two given IDs for equality.  This function uses a constant-time
// comparison algorithm to prevent timing attacks.
func (i ID) Equals(other ID) bool {
	return subtle.ConstantTimeCompare(i[:], other[:]) == 1
}

// Implements the `TextMarshaler` interface from the encoding package.
func (i *ID) MarshalText() ([]byte, error) {
	return []byte(i.String()), nil
}

// Implements the `TextUnmarshaler` interface from the encoding package.
func (i *ID) UnmarshalText(bs []byte) (err error) {
	// Convert to the canonical encoding - uppercase, no '=', no chunks, and
	// with any potential typos fixed.
	id := string(bs)
	id = strings.Trim(id, "=")
	id = strings.ToUpper(id)
	id = untypeoify(id)
	id = unchunkify(id)

	if len(id) != 56 {
		return errors.New("device ID invalid: incorrect length")
	}

	// Remove & verify Luhn check digits
	id, err = unluhnify(id)
	if err != nil {
		return err
	}

	// Base32 decode
	dec, err := base32.StdEncoding.DecodeString(id + "====")
	if err != nil {
		return err
	}

	// Done!
	copy(i[:], dec)
	return nil
}

// Add Luhn check digits to a string, returning the new one.
func luhnify(s string) (string, error) {
	if len(s) != 52 {
		panic("unsupported string length")
	}

	// Split the string into chunks of length 13, and add a Luhn check digit to
	// each one.
	res := make([]string, 0, 4)
	for i := 0; i < 4; i++ {
		chunk := s[i*13 : (i+1)*13]

		l, err := luhn.Base32.Generate(chunk)
		if err != nil {
			return "", err
		}

		res = append(res, fmt.Sprintf("%s%c", chunk, l))
	}

	return res[0] + res[1] + res[2] + res[3], nil
}

// Remove Luhn check digits from the given string, validating that they are
// correct.
func unluhnify(s string) (string, error) {
	if len(s) != 56 {
		return "", fmt.Errorf("unsupported string length %d", len(s))
	}

	res := make([]string, 0, 4)
	for i := 0; i < 4; i++ {
		// 13 characters, plus the Luhn digit.
		chunk := s[i*14 : (i+1)*14]

		// Get the expected check digit.
		l, err := luhn.Base32.Generate(chunk[0:13])
		if err != nil {
			return "", err
		}

		// Validate the digits match.
		if fmt.Sprintf("%c", l) != chunk[13:] {
			return "", errors.New("check digit incorrect")
		}

		res = append(res, chunk[0:13])
	}

	return res[0] + res[1] + res[2] + res[3], nil
}

// Returns a string split into chunks of size 7.
func chunkify(s string) string {
	s = regexp.MustCompile("(.{7})").ReplaceAllString(s, "$1-")
	s = strings.Trim(s, "-")
	return s
}

// Un-chunks a string by removing all hyphens and spaces.
func unchunkify(s string) string {
	s = strings.Replace(s, "-", "", -1)
	s = strings.Replace(s, " ", "", -1)
	return s
}

// We use base32 encoding, which uses 26 characters, and then the numbers
// 234567.  This is useful since the alphabet doesn't contain the numbers 0, 1,
// or 8, which means we can replace them with their letter-lookalikes.
func untypeoify(s string) string {
	s = strings.Replace(s, "0", "O", -1)
	s = strings.Replace(s, "1", "I", -1)
	s = strings.Replace(s, "8", "B", -1)
	return s
}
<|endoftext|>


<commit_before>// Copyright 2013 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package id3

import (
	"fmt"
	"io"
)

const (
	HeaderSize = 10
)

// Tag represents an ID3v2 tag
type Tag struct {
	Header
	frames  map[string][]Framer
	padding uint
}

// Creates a new tag
func NewTag(reader io.Reader) *Tag {
	t := &Tag{NewHeader(reader), make(map[string][]Framer), 0}
	if t.Header == nil {
		return nil
	}

	var frame Framer
	size := t.Header.Size()
	for size > 0 {
		switch t.Header.Version() {
		case "2.3.0":
			frame = NewV3Frame(reader)
		default:
			frame = NewV3Frame(reader)
		}

		if frame == nil {
			break
		}

		id := frame.Id()
		t.frames[id] = append(t.frames[id], frame)

		size -= FrameHeaderSize + frame.Size()
	}

	t.padding = uint(size)
	nAdvance := int(t.padding - FrameHeaderSize)
	if n, err := io.ReadFull(reader, make([]byte, nAdvance)); n != nAdvance || err != nil {
		return nil
	}

	return t
}

// Size of the tag
// Recalculated as frames and padding can be changed
func (t Tag) Size() int {
	size := 0
	for _, v := range t.frames {
		for _, f := range v {
			size += FrameHeaderSize + f.Size()
		}
	}

	headerSize := t.Header.Size()
	if padding := headerSize - size; padding < 0 {
		t.padding = 0
		head := t.Header.(Head)
		head.size = int32(size)
		return size
	} else {
		t.padding = uint(padding)
		return headerSize
	}
}

func (t Tag) Bytes() []byte {
	data := make([]byte, t.Size())

	index := 0
	for _, v := range t.frames {
		for _, f := range v {
			size := FrameHeaderSize + f.Size()

			switch t.Header.Version() {
			case "2.3":
				copy(data[index:index+size], V3Bytes(f))
			default:
				copy(data[index:index+size], V3Bytes(f))
			}

			index += size
		}
	}

	return append(t.Header.Bytes(), data...)
}

// All frames
func (t Tag) Frames(id string) []Framer {
	if frames, ok := t.frames[id]; ok && frames != nil {
		return frames
	}

	return nil
}

// First frame
func (t Tag) Frame(id string) Framer {
	if frames := t.Frames(id); frames != nil {
		return frames[0]
	}

	return nil
}

// Delete and return all frames
func (t *Tag) DeleteFrames(id string) []Framer {
	frames := t.Frames(id)
	if frames == nil {
		return nil
	}

	delete(t.frames, id)

	return frames
}

// Add frame
func (t *Tag) AddFrame(frame Framer) {
	id := frame.Id()
	t.frames[id] = append(t.frames[id], frame)
}

// Header represents the useful information contained in the data
type Header interface {
	Version() string
	Size() int
	Bytes() []byte
}

func (t Tag) Title() string {
	return t.textFrameText("TIT2")
}

func (t Tag) Artist() string {
	return t.textFrameText("TPE1")
}

func (t Tag) Album() string {
	return t.textFrameText("TALB")
}

func (t Tag) Year() string {
	return t.textFrameText("TYER")
}

func (t Tag) Genre() string {
	return t.textFrameText("TCON")
}

func (t *Tag) SetTitle(text string) {
	t.setTextFrameText("TIT2", text)
}

func (t *Tag) SetArtist(text string) {
	t.setTextFrameText("TPE1", text)
}

func (t *Tag) SetAlbum(text string) {
	t.setTextFrameText("TALB", text)
}

func (t *Tag) SetGenre(text string) {
	t.setTextFrameText("TCON", text)
}

func (t *Tag) SetYear(text string) {
	t.setTextFrameText("TYER", text)
}

func (t Tag) textFrameText(id string) string {
	if frame := t.Frame(id); frame != nil {
		switch frame.(type) {
		case (*TextFrame):
			return frame.(*TextFrame).Text()
		default:
		}
	}

	return ""
}

func (t *Tag) setTextFrameText(id, text string) {
	if frame := t.Frame(id); frame != nil {
		switch frame.(type) {
		case (*TextFrame):
			frame.(*TextFrame).SetText(text)
		default:
		}
	}
}

func NewHeader(reader io.Reader) Header {
	data := make([]byte, HeaderSize)
	n, err := io.ReadFull(reader, data)
	if n < HeaderSize || err != nil || string(data[:3]) != "ID3" {
		return nil
	}

	size, err := synchint(data[6:])
	if err != nil {
		return nil
	}

	return Head{
		version:  data[3],
		revision: data[4],
		flags:    data[5],
		size:     size,
	}
}

// Head represents the data of the header of the entire tag
type Head struct {
	version, revision byte
	flags             byte
	size              int32
}

func (h Head) Version() string {
	return fmt.Sprintf("2.%d.%d", h.version, h.revision)
}

func (h Head) Size() int {
	return int(h.size)
}

func (h Head) Bytes() []byte {
	data := make([]byte, HeaderSize)

	copy(data[:3], []byte("ID3"))
	copy(data[6:], synchbytes(h.size))
	data[3] = h.version
	data[4] = h.revision
	data[5] = h.flags

	return data
}
<commit_msg>Add intermediate text frame helper<commit_after>// Copyright 2013 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package id3

import (
	"fmt"
	"io"
)

const (
	HeaderSize = 10
)

// Tag represents an ID3v2 tag
type Tag struct {
	Header
	frames  map[string][]Framer
	padding uint
}

// Creates a new tag
func NewTag(reader io.Reader) *Tag {
	t := &Tag{NewHeader(reader), make(map[string][]Framer), 0}
	if t.Header == nil {
		return nil
	}

	var frame Framer
	size := t.Header.Size()
	for size > 0 {
		switch t.Header.Version() {
		case "2.3.0":
			frame = NewV3Frame(reader)
		default:
			frame = NewV3Frame(reader)
		}

		if frame == nil {
			break
		}

		id := frame.Id()
		t.frames[id] = append(t.frames[id], frame)

		size -= FrameHeaderSize + frame.Size()
	}

	t.padding = uint(size)
	nAdvance := int(t.padding - FrameHeaderSize)
	if n, err := io.ReadFull(reader, make([]byte, nAdvance)); n != nAdvance || err != nil {
		return nil
	}

	return t
}

// Size of the tag
// Recalculated as frames and padding can be changed
func (t Tag) Size() int {
	size := 0
	for _, v := range t.frames {
		for _, f := range v {
			size += FrameHeaderSize + f.Size()
		}
	}

	headerSize := t.Header.Size()
	if padding := headerSize - size; padding < 0 {
		t.padding = 0
		head := t.Header.(Head)
		head.size = int32(size)
		return size
	} else {
		t.padding = uint(padding)
		return headerSize
	}
}

func (t Tag) Bytes() []byte {
	data := make([]byte, t.Size())

	index := 0
	for _, v := range t.frames {
		for _, f := range v {
			size := FrameHeaderSize + f.Size()

			switch t.Header.Version() {
			case "2.3":
				copy(data[index:index+size], V3Bytes(f))
			default:
				copy(data[index:index+size], V3Bytes(f))
			}

			index += size
		}
	}

	return append(t.Header.Bytes(), data...)
}

// All frames
func (t Tag) Frames(id string) []Framer {
	if frames, ok := t.frames[id]; ok && frames != nil {
		return frames
	}

	return nil
}

// First frame
func (t Tag) Frame(id string) Framer {
	if frames := t.Frames(id); frames != nil {
		return frames[0]
	}

	return nil
}

// Delete and return all frames
func (t *Tag) DeleteFrames(id string) []Framer {
	frames := t.Frames(id)
	if frames == nil {
		return nil
	}

	delete(t.frames, id)

	return frames
}

// Add frame
func (t *Tag) AddFrame(frame Framer) {
	id := frame.Id()
	t.frames[id] = append(t.frames[id], frame)
}

// Header represents the useful information contained in the data
type Header interface {
	Version() string
	Size() int
	Bytes() []byte
}

func (t Tag) Title() string {
	return t.textFrameText("TIT2")
}

func (t Tag) Artist() string {
	return t.textFrameText("TPE1")
}

func (t Tag) Album() string {
	return t.textFrameText("TALB")
}

func (t Tag) Year() string {
	return t.textFrameText("TYER")
}

func (t Tag) Genre() string {
	return t.textFrameText("TCON")
}

func (t *Tag) SetTitle(text string) {
	t.setTextFrameText("TIT2", text)
}

func (t *Tag) SetArtist(text string) {
	t.setTextFrameText("TPE1", text)
}

func (t *Tag) SetAlbum(text string) {
	t.setTextFrameText("TALB", text)
}

func (t *Tag) SetGenre(text string) {
	t.setTextFrameText("TCON", text)
}

func (t *Tag) SetYear(text string) {
	t.setTextFrameText("TYER", text)
}

func (t *Tag) textFrame(id string) *TextFrame {
	if frame := t.Frame(id); frame != nil {
		switch frame.(type) {
		case (*TextFrame):
			return frame.(*TextFrame)
		default:
		}
	}

	return nil
}

func (t Tag) textFrameText(id string) string {
	if frame := t.textFrame(id); frame != nil {
		return frame.Text()
	}

	return ""
}

func (t *Tag) setTextFrameText(id, text string) {
	if frame := t.textFrame(id); frame != nil {
		frame.SetText(text)
	}
}

func NewHeader(reader io.Reader) Header {
	data := make([]byte, HeaderSize)
	n, err := io.ReadFull(reader, data)
	if n < HeaderSize || err != nil || string(data[:3]) != "ID3" {
		return nil
	}

	size, err := synchint(data[6:])
	if err != nil {
		return nil
	}

	return Head{
		version:  data[3],
		revision: data[4],
		flags:    data[5],
		size:     size,
	}
}

// Head represents the data of the header of the entire tag
type Head struct {
	version, revision byte
	flags             byte
	size              int32
}

func (h Head) Version() string {
	return fmt.Sprintf("2.%d.%d", h.version, h.revision)
}

func (h Head) Size() int {
	return int(h.size)
}

func (h Head) Bytes() []byte {
	data := make([]byte, HeaderSize)

	copy(data[:3], []byte("ID3"))
	copy(data[6:], synchbytes(h.size))
	data[3] = h.version
	data[4] = h.revision
	data[5] = h.flags

	return data
}
<|endoftext|>


<commit_before>package actions_test

import (
	"simplejsondb/actions"
	"simplejsondb/core"
	"simplejsondb/dbio"

	"fmt"
	utils "test_utils"
	"testing"
)

func TestRecordAllocator_Add(t *testing.T) {
	blocks := [][]byte{
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
		nil,
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
	}
	fakeDataFile := utils.NewFakeDataFile(blocks)
	dataBuffer := dbio.NewDataBuffer(fakeDataFile, 4)
	repo := core.NewDataBlockRepository(dataBuffer)

	controlBlock := repo.ControlBlock()
	controlBlock.Format()
	dataBuffer.MarkAsDirty(controlBlock.DataBlockID())
	blockMap := repo.DataBlocksMap()
	for i := uint16(0); i < 4; i++ {
		blockMap.MarkAsUsed(i)
	}

	allocator := actions.NewRecordAllocator(dataBuffer)

	// Fill up a datablock up to its limit
	maxData := dbio.DATABLOCK_SIZE - core.MIN_UTILIZATION - core.RECORD_HEADER_SIZE
	contents := ""
	for i := uint16(0); i < maxData; i++ {
		contents += fmt.Sprintf("%d", i%10)
	}
	allocator.Add(&core.Record{uint32(1), contents})

	// Add a new record that will go into the next datablock on the list
	allocator.Add(&core.Record{uint32(2), "Some data"})

	// Flush data to data blocks and ensure that things work after a reload
	dataBuffer.Sync()
	dataBuffer = dbio.NewDataBuffer(fakeDataFile, 4)
	repo = core.NewDataBlockRepository(dataBuffer)
	blockMap = repo.DataBlocksMap()

	// Ensure new blocks has been marked as used
	if !blockMap.IsInUse(3) || !blockMap.IsInUse(4) {
		t.Errorf("Blocks 3 and 4 should have been marked as in use")
	}

	// Ensure the blocks point to each other
	firstRecordBlock := repo.RecordBlock(3)
	if firstRecordBlock.NextBlockID() != 4 {
		t.Errorf("First allocated block does not point to the next one")
	}
	secondRecordBlock := repo.RecordBlock(4)
	if secondRecordBlock.PrevBlockID() != 3 {
		t.Errorf("Second allocated block does not point to the previous one")
	}

	// Ensure the pointer for the next datablock that has free space has been updated
	controlBlock = repo.ControlBlock()
	if controlBlock.NextAvailableRecordsDataBlockID() != 4 {
		t.Errorf("Did not update the pointer to the next datablock that has allows insertion")
	}
}

func TestRecordAllocator_Remove(t *testing.T) {
	blocks := [][]byte{
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
		nil,
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
	}
	fakeDataFile := utils.NewFakeDataFile(blocks)
	dataBuffer := dbio.NewDataBuffer(fakeDataFile, 10)
	repo := core.NewDataBlockRepository(dataBuffer)
	controlBlock := repo.ControlBlock()
	controlBlock.Format()
	dataBuffer.MarkAsDirty(controlBlock.DataBlockID())

	blockMap := repo.DataBlocksMap()
	for i := uint16(0); i < 4; i++ {
		blockMap.MarkAsUsed(i)
	}

	allocator := actions.NewRecordAllocator(dataBuffer)

	// Prepare data to fill up a datablock up to its limit
	maxData := dbio.DATABLOCK_SIZE - core.MIN_UTILIZATION - core.RECORD_HEADER_SIZE
	contents := ""
	for i := uint16(0); i < maxData; i++ {
		contents += fmt.Sprintf("%d", i%10)
	}

	// Insert data into 3 different blocks
	allocator.Add(&core.Record{uint32(3), contents})
	allocator.Add(&core.Record{uint32(4), contents})
	allocator.Add(&core.Record{uint32(5), contents})
	allocator.Add(&core.Record{uint32(6), "Some data"})
	allocator.Add(&core.Record{uint32(7), "More data"})

	// Free up some datablocks
	allocator.Remove(core.RowID{DataBlockID: 3, LocalID: 0})
	allocator.Remove(core.RowID{DataBlockID: 5, LocalID: 0})

	// Free part of another datablock
	allocator.Remove(core.RowID{DataBlockID: 6, LocalID: 0})

	// Flush data to data blocks and ensure that things work after a reload
	dataBuffer.Sync()

	dataBuffer = dbio.NewDataBuffer(fakeDataFile, 4)
	repo = core.NewDataBlockRepository(dataBuffer)
	blockMap = repo.DataBlocksMap()

	// Ensure blocks have been marked as free again
	if blockMap.IsInUse(3) {
		t.Errorf("Block 3 should have been marked as free")
	}
	if blockMap.IsInUse(5) {
		t.Errorf("Block 5 should have been marked as free")
	}

	// Ensure the linked list is set up properly
	// First records datablock is now at block 4
	controlBlock = repo.ControlBlock()
	if controlBlock.FirstRecordDataBlock() != 4 {
		t.Fatal("First record datablock is set to the wrong block")
	}

	// Then the next block on the chain is at block 6
	recordBlock := repo.RecordBlock(4)
	if recordBlock.NextBlockID() != 6 {
		t.Fatal("First record datablock next block pointer is set to the wrong block")
	}

	// And the block 6 points back to the block 4
	recordBlock = repo.RecordBlock(6)
	if recordBlock.PrevBlockID() != 4 {
		t.Fatal("Second record datablock previous block pointer is incorrect")
	}
}

func TestRecordAllocator_Update(t *testing.T) {
	blocks := [][]byte{
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
		nil,
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
	}
	fakeDataFile := utils.NewFakeDataFile(blocks)
	dataBuffer := dbio.NewDataBuffer(fakeDataFile, 4)
	repo := core.NewDataBlockRepository(dataBuffer)
	controlBlock := repo.ControlBlock()
	controlBlock.Format()
	dataBuffer.MarkAsDirty(controlBlock.DataBlockID())

	blockMap := repo.DataBlocksMap()
	for i := uint16(0); i < 4; i++ {
		blockMap.MarkAsUsed(i)
	}

	allocator := actions.NewRecordAllocator(dataBuffer)

	// Fill up a datablock up to its limit
	maxData := dbio.DATABLOCK_SIZE - core.MIN_UTILIZATION - core.RECORD_HEADER_SIZE
	contents := ""
	for i := uint16(0); i < maxData; i++ {
		contents += fmt.Sprintf("%d", i%10)
	}
	allocator.Add(&core.Record{1, contents})

	// Add a new record that will go into the next datablock on the list
	allocator.Add(&core.Record{2, "Some data"})

	// Update records
	rowID := core.RowID{RecordID: 1, DataBlockID: 3, LocalID: 0}
	if err := allocator.Update(rowID, &core.Record{ID: 1, Data: "NEW CONTENTS"}); err != nil {
		t.Fatal(err)
	}
	rowID = core.RowID{RecordID: 2, DataBlockID: 4, LocalID: 0}
	if err := allocator.Update(rowID, &core.Record{ID: 2, Data: "EVEN MORE!"}); err != nil {
		t.Fatal(err)
	}

	// Flush data to data blocks and ensure that things work after a reload
	dataBuffer.Sync()
	dataBuffer = dbio.NewDataBuffer(fakeDataFile, 4)
	repo = core.NewDataBlockRepository(dataBuffer)
	blockMap = repo.DataBlocksMap()

	// Ensure blocks have been updated
	recordBlock := repo.RecordBlock(3)
	data, err := recordBlock.ReadRecordData(0)
	if err != nil {
		t.Fatal(err)
	}
	if data != "NEW CONTENTS" {
		t.Errorf("First record did not get updated, read `%s`", data)
	}

	recordBlock = repo.RecordBlock(4)
	data, err = recordBlock.ReadRecordData(0)
	if err != nil {
		t.Fatal(err)
	}
	if data != "EVEN MORE!" {
		t.Errorf("Second record did not get updated, read `%s`", data)
	}
}

func TestRecordAllocator_ChainedRows(t *testing.T) {
	blocks := [][]byte{
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
		nil,
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
	}
	fakeDataFile := utils.NewFakeDataFile(blocks)
	dataBuffer := dbio.NewDataBuffer(fakeDataFile, 10)
	repo := core.NewDataBlockRepository(dataBuffer)

	controlBlock := repo.ControlBlock()
	controlBlock.Format()
	dataBuffer.MarkAsDirty(controlBlock.DataBlockID())
	blockMap := repo.DataBlocksMap()
	for i := uint16(0); i < 4; i++ {
		blockMap.MarkAsUsed(i)
	}

	allocator := actions.NewRecordAllocator(dataBuffer)

	// Prepare data to fill up a datablock close to its limit
	maxData := dbio.DATABLOCK_SIZE - core.MIN_UTILIZATION - core.RECORD_HEADER_SIZE
	contents := ""
	for i := uint16(0); i < maxData; i++ {
		contents += fmt.Sprintf("%d", i%10)
	}

	// Insert data into 3 different blocks
	dummy, _ := allocator.Add(&core.Record{uint32(3), contents[0:maxData-100]})
	chainedRowRowID, _ := allocator.Add(&core.Record{uint32(4), contents})
	removedChainedRowID, _ := allocator.Add(&core.Record{uint32(5), contents})
	allocator.Add(&core.Record{uint32(6), "Some data"})
	allocator.Add(&core.Record{uint32(7), "More data"})

	// Ensure that the blocks are chained
	if dummy.DataBlockID != chainedRowRowID.DataBlockID {
		t.Fatalf("Did not create a chained row, expected record to be written on block %d but was written on block %d", dummy.DataBlockID, chainedRowRowID.DataBlockID)
	}

	// Ensure we exercise the code path that deletes chained rows
	allocator.Remove(dummy)
	allocator.Remove(removedChainedRowID)

	// Flush data to data blocks and ensure that things work after a reload
	dataBuffer.Sync()
	dataBuffer = dbio.NewDataBuffer(fakeDataFile, 10)
	repo = core.NewDataBlockRepository(dataBuffer)
	blockMap = repo.DataBlocksMap()
	allocator = actions.NewRecordAllocator(dataBuffer)

	// Ensure the records can be read after a reload
	recordBlock := repo.RecordBlock(chainedRowRowID.DataBlockID)
	first, err := recordBlock.ReadRecordData(chainedRowRowID.LocalID)
	if err != nil {
		t.Fatal(err)
	}
	chainedRowID, err := recordBlock.ChainedRowID(chainedRowRowID.LocalID)
	if err != nil {
		t.Fatal(err)
	}
	recordBlock = repo.RecordBlock(chainedRowID.DataBlockID)
	second, err := recordBlock.ReadRecordData(chainedRowID.LocalID)
	if first+second != contents {
		t.Errorf("Invalid contents found for record, found `%s` and `%s`, expected `%s`", first, second, contents)
	}

	// Ensure deletes clear out headers properly
	recordBlock = repo.RecordBlock(removedChainedRowID.DataBlockID)
	if _, err = recordBlock.ReadRecordData(removedChainedRowID.LocalID); err == nil {
		t.Fatal("Did not clear out the record header of one of the a chained rows deleted")
	}
	recordBlock = repo.RecordBlock(removedChainedRowID.DataBlockID + 1)
	if _, err = recordBlock.ReadRecordData(0); err == nil {
		t.Fatal("Did not clear out the record header of the next block of the chained row")
	}

	dataBuffer.Sync()
	dataBuffer = dbio.NewDataBuffer(fakeDataFile, 10)
	repo = core.NewDataBlockRepository(dataBuffer)
	allocator = actions.NewRecordAllocator(dataBuffer)

	// Add and update a chained row that spans 3 blocks
	bigContents := contents + contents + contents
	chainedUpdateRowID, _ := allocator.Add(&core.Record{uint32(9), bigContents})

	// Keep track of the list of the following row ids of the chained row
	rowIDs := []core.RowID{}
	recordBlock = repo.RecordBlock(chainedUpdateRowID.DataBlockID)
	nextRowID, err := recordBlock.ChainedRowID(chainedUpdateRowID.LocalID)
	if err != nil {
		t.Fatal(err)
	}
	rowIDs = append(rowIDs, nextRowID)

	recordBlock = repo.RecordBlock(nextRowID.DataBlockID)
	nextRowID, err = recordBlock.ChainedRowID(nextRowID.LocalID)
	if err != nil {
		t.Fatal(err)
	}
	rowIDs = append(rowIDs, nextRowID)
	if len(rowIDs) != 2 {
		t.Errorf("Spread record on more blocks than expected %+v", rowIDs)
	}

	// Change record to be really small
	allocator.Update(chainedUpdateRowID, &core.Record{ID: chainedUpdateRowID.RecordID, Data: "a string"})

	// Ensure the next element on the chained row list got cleared
	for _, rowID := range rowIDs {
		_, err := repo.RecordBlock(rowID.DataBlockID).ReadRecordData(rowID.LocalID)
		if err == nil {
			t.Errorf("Did not clear chained row %+v", rowID)
		}
	}

	// Ensure we can read it
	recordBlock = repo.RecordBlock(chainedUpdateRowID.DataBlockID)
	data, _ := recordBlock.ReadRecordData(chainedRowID.LocalID)
	if data != "a string" {
		t.Error("Invalid contents found for record")
	}
}
<commit_msg>go fmt ./...<commit_after>package actions_test

import (
	"simplejsondb/actions"
	"simplejsondb/core"
	"simplejsondb/dbio"

	"fmt"
	utils "test_utils"
	"testing"
)

func TestRecordAllocator_Add(t *testing.T) {
	blocks := [][]byte{
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
		nil,
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
	}
	fakeDataFile := utils.NewFakeDataFile(blocks)
	dataBuffer := dbio.NewDataBuffer(fakeDataFile, 4)
	repo := core.NewDataBlockRepository(dataBuffer)

	controlBlock := repo.ControlBlock()
	controlBlock.Format()
	dataBuffer.MarkAsDirty(controlBlock.DataBlockID())
	blockMap := repo.DataBlocksMap()
	for i := uint16(0); i < 4; i++ {
		blockMap.MarkAsUsed(i)
	}

	allocator := actions.NewRecordAllocator(dataBuffer)

	// Fill up a datablock up to its limit
	maxData := dbio.DATABLOCK_SIZE - core.MIN_UTILIZATION - core.RECORD_HEADER_SIZE
	contents := ""
	for i := uint16(0); i < maxData; i++ {
		contents += fmt.Sprintf("%d", i%10)
	}
	allocator.Add(&core.Record{uint32(1), contents})

	// Add a new record that will go into the next datablock on the list
	allocator.Add(&core.Record{uint32(2), "Some data"})

	// Flush data to data blocks and ensure that things work after a reload
	dataBuffer.Sync()
	dataBuffer = dbio.NewDataBuffer(fakeDataFile, 4)
	repo = core.NewDataBlockRepository(dataBuffer)
	blockMap = repo.DataBlocksMap()

	// Ensure new blocks has been marked as used
	if !blockMap.IsInUse(3) || !blockMap.IsInUse(4) {
		t.Errorf("Blocks 3 and 4 should have been marked as in use")
	}

	// Ensure the blocks point to each other
	firstRecordBlock := repo.RecordBlock(3)
	if firstRecordBlock.NextBlockID() != 4 {
		t.Errorf("First allocated block does not point to the next one")
	}
	secondRecordBlock := repo.RecordBlock(4)
	if secondRecordBlock.PrevBlockID() != 3 {
		t.Errorf("Second allocated block does not point to the previous one")
	}

	// Ensure the pointer for the next datablock that has free space has been updated
	controlBlock = repo.ControlBlock()
	if controlBlock.NextAvailableRecordsDataBlockID() != 4 {
		t.Errorf("Did not update the pointer to the next datablock that has allows insertion")
	}
}

func TestRecordAllocator_Remove(t *testing.T) {
	blocks := [][]byte{
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
		nil,
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
	}
	fakeDataFile := utils.NewFakeDataFile(blocks)
	dataBuffer := dbio.NewDataBuffer(fakeDataFile, 10)
	repo := core.NewDataBlockRepository(dataBuffer)
	controlBlock := repo.ControlBlock()
	controlBlock.Format()
	dataBuffer.MarkAsDirty(controlBlock.DataBlockID())

	blockMap := repo.DataBlocksMap()
	for i := uint16(0); i < 4; i++ {
		blockMap.MarkAsUsed(i)
	}

	allocator := actions.NewRecordAllocator(dataBuffer)

	// Prepare data to fill up a datablock up to its limit
	maxData := dbio.DATABLOCK_SIZE - core.MIN_UTILIZATION - core.RECORD_HEADER_SIZE
	contents := ""
	for i := uint16(0); i < maxData; i++ {
		contents += fmt.Sprintf("%d", i%10)
	}

	// Insert data into 3 different blocks
	allocator.Add(&core.Record{uint32(3), contents})
	allocator.Add(&core.Record{uint32(4), contents})
	allocator.Add(&core.Record{uint32(5), contents})
	allocator.Add(&core.Record{uint32(6), "Some data"})
	allocator.Add(&core.Record{uint32(7), "More data"})

	// Free up some datablocks
	allocator.Remove(core.RowID{DataBlockID: 3, LocalID: 0})
	allocator.Remove(core.RowID{DataBlockID: 5, LocalID: 0})

	// Free part of another datablock
	allocator.Remove(core.RowID{DataBlockID: 6, LocalID: 0})

	// Flush data to data blocks and ensure that things work after a reload
	dataBuffer.Sync()

	dataBuffer = dbio.NewDataBuffer(fakeDataFile, 4)
	repo = core.NewDataBlockRepository(dataBuffer)
	blockMap = repo.DataBlocksMap()

	// Ensure blocks have been marked as free again
	if blockMap.IsInUse(3) {
		t.Errorf("Block 3 should have been marked as free")
	}
	if blockMap.IsInUse(5) {
		t.Errorf("Block 5 should have been marked as free")
	}

	// Ensure the linked list is set up properly
	// First records datablock is now at block 4
	controlBlock = repo.ControlBlock()
	if controlBlock.FirstRecordDataBlock() != 4 {
		t.Fatal("First record datablock is set to the wrong block")
	}

	// Then the next block on the chain is at block 6
	recordBlock := repo.RecordBlock(4)
	if recordBlock.NextBlockID() != 6 {
		t.Fatal("First record datablock next block pointer is set to the wrong block")
	}

	// And the block 6 points back to the block 4
	recordBlock = repo.RecordBlock(6)
	if recordBlock.PrevBlockID() != 4 {
		t.Fatal("Second record datablock previous block pointer is incorrect")
	}
}

func TestRecordAllocator_Update(t *testing.T) {
	blocks := [][]byte{
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
		nil,
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
	}
	fakeDataFile := utils.NewFakeDataFile(blocks)
	dataBuffer := dbio.NewDataBuffer(fakeDataFile, 4)
	repo := core.NewDataBlockRepository(dataBuffer)
	controlBlock := repo.ControlBlock()
	controlBlock.Format()
	dataBuffer.MarkAsDirty(controlBlock.DataBlockID())

	blockMap := repo.DataBlocksMap()
	for i := uint16(0); i < 4; i++ {
		blockMap.MarkAsUsed(i)
	}

	allocator := actions.NewRecordAllocator(dataBuffer)

	// Fill up a datablock up to its limit
	maxData := dbio.DATABLOCK_SIZE - core.MIN_UTILIZATION - core.RECORD_HEADER_SIZE
	contents := ""
	for i := uint16(0); i < maxData; i++ {
		contents += fmt.Sprintf("%d", i%10)
	}
	allocator.Add(&core.Record{1, contents})

	// Add a new record that will go into the next datablock on the list
	allocator.Add(&core.Record{2, "Some data"})

	// Update records
	rowID := core.RowID{RecordID: 1, DataBlockID: 3, LocalID: 0}
	if err := allocator.Update(rowID, &core.Record{ID: 1, Data: "NEW CONTENTS"}); err != nil {
		t.Fatal(err)
	}
	rowID = core.RowID{RecordID: 2, DataBlockID: 4, LocalID: 0}
	if err := allocator.Update(rowID, &core.Record{ID: 2, Data: "EVEN MORE!"}); err != nil {
		t.Fatal(err)
	}

	// Flush data to data blocks and ensure that things work after a reload
	dataBuffer.Sync()
	dataBuffer = dbio.NewDataBuffer(fakeDataFile, 4)
	repo = core.NewDataBlockRepository(dataBuffer)
	blockMap = repo.DataBlocksMap()

	// Ensure blocks have been updated
	recordBlock := repo.RecordBlock(3)
	data, err := recordBlock.ReadRecordData(0)
	if err != nil {
		t.Fatal(err)
	}
	if data != "NEW CONTENTS" {
		t.Errorf("First record did not get updated, read `%s`", data)
	}

	recordBlock = repo.RecordBlock(4)
	data, err = recordBlock.ReadRecordData(0)
	if err != nil {
		t.Fatal(err)
	}
	if data != "EVEN MORE!" {
		t.Errorf("Second record did not get updated, read `%s`", data)
	}
}

func TestRecordAllocator_ChainedRows(t *testing.T) {
	blocks := [][]byte{
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
		nil,
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
		make([]byte, dbio.DATABLOCK_SIZE),
	}
	fakeDataFile := utils.NewFakeDataFile(blocks)
	dataBuffer := dbio.NewDataBuffer(fakeDataFile, 10)
	repo := core.NewDataBlockRepository(dataBuffer)

	controlBlock := repo.ControlBlock()
	controlBlock.Format()
	dataBuffer.MarkAsDirty(controlBlock.DataBlockID())
	blockMap := repo.DataBlocksMap()
	for i := uint16(0); i < 4; i++ {
		blockMap.MarkAsUsed(i)
	}

	allocator := actions.NewRecordAllocator(dataBuffer)

	// Prepare data to fill up a datablock close to its limit
	maxData := dbio.DATABLOCK_SIZE - core.MIN_UTILIZATION - core.RECORD_HEADER_SIZE
	contents := ""
	for i := uint16(0); i < maxData; i++ {
		contents += fmt.Sprintf("%d", i%10)
	}

	// Insert data into 3 different blocks
	dummy, _ := allocator.Add(&core.Record{uint32(3), contents[0 : maxData-100]})
	chainedRowRowID, _ := allocator.Add(&core.Record{uint32(4), contents})
	removedChainedRowID, _ := allocator.Add(&core.Record{uint32(5), contents})
	allocator.Add(&core.Record{uint32(6), "Some data"})
	allocator.Add(&core.Record{uint32(7), "More data"})

	// Ensure that the blocks are chained
	if dummy.DataBlockID != chainedRowRowID.DataBlockID {
		t.Fatalf("Did not create a chained row, expected record to be written on block %d but was written on block %d", dummy.DataBlockID, chainedRowRowID.DataBlockID)
	}

	// Ensure we exercise the code path that deletes chained rows
	allocator.Remove(dummy)
	allocator.Remove(removedChainedRowID)

	// Flush data to data blocks and ensure that things work after a reload
	dataBuffer.Sync()
	dataBuffer = dbio.NewDataBuffer(fakeDataFile, 10)
	repo = core.NewDataBlockRepository(dataBuffer)
	blockMap = repo.DataBlocksMap()
	allocator = actions.NewRecordAllocator(dataBuffer)

	// Ensure the records can be read after a reload
	recordBlock := repo.RecordBlock(chainedRowRowID.DataBlockID)
	first, err := recordBlock.ReadRecordData(chainedRowRowID.LocalID)
	if err != nil {
		t.Fatal(err)
	}
	chainedRowID, err := recordBlock.ChainedRowID(chainedRowRowID.LocalID)
	if err != nil {
		t.Fatal(err)
	}
	recordBlock = repo.RecordBlock(chainedRowID.DataBlockID)
	second, err := recordBlock.ReadRecordData(chainedRowID.LocalID)
	if first+second != contents {
		t.Errorf("Invalid contents found for record, found `%s` and `%s`, expected `%s`", first, second, contents)
	}

	// Ensure deletes clear out headers properly
	recordBlock = repo.RecordBlock(removedChainedRowID.DataBlockID)
	if _, err = recordBlock.ReadRecordData(removedChainedRowID.LocalID); err == nil {
		t.Fatal("Did not clear out the record header of one of the a chained rows deleted")
	}
	recordBlock = repo.RecordBlock(removedChainedRowID.DataBlockID + 1)
	if _, err = recordBlock.ReadRecordData(0); err == nil {
		t.Fatal("Did not clear out the record header of the next block of the chained row")
	}

	dataBuffer.Sync()
	dataBuffer = dbio.NewDataBuffer(fakeDataFile, 10)
	repo = core.NewDataBlockRepository(dataBuffer)
	allocator = actions.NewRecordAllocator(dataBuffer)

	// Add and update a chained row that spans 3 blocks
	bigContents := contents + contents + contents
	chainedUpdateRowID, _ := allocator.Add(&core.Record{uint32(9), bigContents})

	// Keep track of the list of the following row ids of the chained row
	rowIDs := []core.RowID{}
	recordBlock = repo.RecordBlock(chainedUpdateRowID.DataBlockID)
	nextRowID, err := recordBlock.ChainedRowID(chainedUpdateRowID.LocalID)
	if err != nil {
		t.Fatal(err)
	}
	rowIDs = append(rowIDs, nextRowID)

	recordBlock = repo.RecordBlock(nextRowID.DataBlockID)
	nextRowID, err = recordBlock.ChainedRowID(nextRowID.LocalID)
	if err != nil {
		t.Fatal(err)
	}
	rowIDs = append(rowIDs, nextRowID)
	if len(rowIDs) != 2 {
		t.Errorf("Spread record on more blocks than expected %+v", rowIDs)
	}

	// Change record to be really small
	allocator.Update(chainedUpdateRowID, &core.Record{ID: chainedUpdateRowID.RecordID, Data: "a string"})

	// Ensure the next element on the chained row list got cleared
	for _, rowID := range rowIDs {
		_, err := repo.RecordBlock(rowID.DataBlockID).ReadRecordData(rowID.LocalID)
		if err == nil {
			t.Errorf("Did not clear chained row %+v", rowID)
		}
	}

	// Ensure we can read it
	recordBlock = repo.RecordBlock(chainedUpdateRowID.DataBlockID)
	data, _ := recordBlock.ReadRecordData(chainedRowID.LocalID)
	if data != "a string" {
		t.Error("Invalid contents found for record")
	}
}
<|endoftext|>


<commit_before>// Copyright 2012 The Walk 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 main

import (
	"fmt"
	"os"
	"strings"
)

import "github.com/lxn/walk"

type EnvItem struct {
	varName string
	value   string
}

type EnvModel struct{
	walk.ListModelBase
	envItems []EnvItem
	itemsResetPublisher  walk.EventPublisher
	itemChangedPublisher walk.IntEventPublisher
}

func NewEnvModel() *EnvModel{
	em := &EnvModel{}
	em.envItems = make([]EnvItem, 0)
	return em
}

func (em *EnvModel) ItemCount()int{
	return len(em.envItems)
}

func (em *EnvModel) Value( index int) interface{} {
	return em.envItems[index].varName
}

func main() {
	walk.Initialize(walk.InitParams{PanicOnError: true})
	defer walk.Shutdown()

	myWindow, _ := walk.NewMainWindow()

	myWindow.SetLayout(walk.NewVBoxLayout())
	myWindow.SetTitle("Go GUI example")

	splitter, _ := walk.NewSplitter(myWindow)
	splitter.SetOrientation(walk.Vertical)

	lb, _ := walk.NewListBox(splitter)
	//lb.SetHeight(100)

	valueEdit, _ := walk.NewTextEdit(splitter)
	valueEdit.SetReadOnly(true)
	//valueEdit.SetHeight(300)

	buttonCompositor, _ := walk.NewComposite(splitter)
	hbox := walk.NewHBoxLayout()
	buttonCompositor.SetLayout(hbox)

	myButton1, _ := walk.NewPushButton(buttonCompositor)
	myButton1.SetText("New")

	myButton2, _ := walk.NewPushButton(buttonCompositor)
	myButton2.SetText("Edit")

	myButton3, _ := walk.NewPushButton(buttonCompositor)
	myButton3.SetText("Delete")

	//env model
	em := NewEnvModel()

	for _, env := range os.Environ() {
		i := strings.Index(env, "=")
		if i == 0 {
			continue
		}
		varName := env[0:i]
		value := env[i+1:]
		envItem := EnvItem{varName, value}

		em.envItems = append(em.envItems, envItem)
	}

	fmt.Println("The len of Model", em.ItemCount())
	lb.SetModel(em)
	lb.CurrentIndexChanged().Attach(func() {
		if curVar, ok := em.Value(lb.CurrentIndex()).(string); ok {
			value := em.envItems[lb.CurrentIndex()].value
			value = strings.Replace(value, ";", "\r\n", -1)
			valueEdit.SetText(value)
			fmt.Println("CurrentIndex:", lb.CurrentIndex())
			fmt.Println("CurrentEnvVarName:",curVar)
		}
	})
	lb.DblClicked().Attach(func() {
		value := em.envItems[lb.CurrentIndex()].value
		value = strings.Replace(value, ";", "\r\n", -1)
		valueEdit.SetText(value)
		walk.MsgBox(myWindow, "About", value, walk.MsgBoxOK|walk.MsgBoxIconInformation)
	})
	myWindow.Show()
	myWindow.SetMinMaxSize(walk.Size{320, 240}, walk.Size{})
	myWindow.SetSize(walk.Size{400, 500})
	myWindow.Run()
}
<commit_msg>proper height<commit_after>// Copyright 2012 The Walk 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 main

import (
	"fmt"
	"os"
	"strings"
)

import "github.com/lxn/walk"

type EnvItem struct {
	varName string
	value   string
}

type EnvModel struct{
	walk.ListModelBase
	envItems []EnvItem
	itemsResetPublisher  walk.EventPublisher
	itemChangedPublisher walk.IntEventPublisher
}

func NewEnvModel() *EnvModel{
	em := &EnvModel{}
	em.envItems = make([]EnvItem, 0)
	return em
}

func (em *EnvModel) ItemCount()int{
	return len(em.envItems)
}

func (em *EnvModel) Value( index int) interface{} {
	return em.envItems[index].varName
}

func main() {
	walk.Initialize(walk.InitParams{PanicOnError: true})
	defer walk.Shutdown()

	myWindow, _ := walk.NewMainWindow()

	myWindow.SetLayout(walk.NewVBoxLayout())
	myWindow.SetTitle("Go GUI example")

	splitter, _ := walk.NewSplitter(myWindow)
	splitter.SetOrientation(walk.Vertical)
	//splitter.SetHeight(270)

	lb, _ := walk.NewListBox(splitter)
	//lb.SetHeight(100)
	//lb.SetMinMaxSize(walk.Size{Width:100, Height:100}, walk.Size{})
	//lb.SetSize(walk.Size{Width:100, Height:100})

	valueEdit, _ := walk.NewTextEdit(splitter)
	valueEdit.SetReadOnly(true)
	//valueEdit.SetHeight(300)

	buttonCompositor, _ := walk.NewComposite(myWindow)
	hbox := walk.NewHBoxLayout()
	buttonCompositor.SetLayout(hbox)
	buttonCompositor.SetHeight(30)

	myButton1, _ := walk.NewPushButton(buttonCompositor)
	myButton1.SetText("New")

	myButton2, _ := walk.NewPushButton(buttonCompositor)
	myButton2.SetText("Edit")

	myButton3, _ := walk.NewPushButton(buttonCompositor)
	myButton3.SetText("Delete")

	//env model
	em := NewEnvModel()

	for _, env := range os.Environ() {
		i := strings.Index(env, "=")
		if i == 0 {
			continue
		}
		varName := env[0:i]
		value := env[i+1:]
		envItem := EnvItem{varName, value}

		em.envItems = append(em.envItems, envItem)
	}

	fmt.Println("The len of Model", em.ItemCount())
	lb.SetModel(em)
	lb.CurrentIndexChanged().Attach(func() {
		if curVar, ok := em.Value(lb.CurrentIndex()).(string); ok {
			value := em.envItems[lb.CurrentIndex()].value
			value = strings.Replace(value, ";", "\r\n", -1)
			valueEdit.SetText(value)
			fmt.Println("CurrentIndex:", lb.CurrentIndex())
			fmt.Println("CurrentEnvVarName:",curVar)
		}
	})
	lb.DblClicked().Attach(func() {
		value := em.envItems[lb.CurrentIndex()].value
		value = strings.Replace(value, ";", "\r\n", -1)
		valueEdit.SetText(value)
		walk.MsgBox(myWindow, "About", value, walk.MsgBoxOK|walk.MsgBoxIconInformation)
	})
	myWindow.Show()
	myWindow.SetMinMaxSize(walk.Size{320, 240}, walk.Size{})
	myWindow.SetSize(walk.Size{400, 500})
	myWindow.Run()
}
<|endoftext|>


<commit_before>package libvirt

import (
	libvirt "github.com/libvirt/libvirt-go"
	libvirtxml "github.com/libvirt/libvirt-go-xml"
	"os"
)

func newFilesystemDef() libvirtxml.DomainFilesystem {
	return libvirtxml.DomainFilesystem{
		Type:       "mount",  // This is the only type used by qemu/kvm
		AccessMode: "mapped", // A safe default value
		ReadOnly:   &libvirtxml.DomainFilesystemReadOnly{},
	}
}

// Creates a domain definition with the defaults
// the provider uses
func newDomainDef() libvirtxml.Domain {
	domainDef := libvirtxml.Domain{
		OS: &libvirtxml.DomainOS{
			Type: &libvirtxml.DomainOSType{
				Type:    "hvm",
				Arch:    "x86_64",
				Machine: "pc",
			},
		},
		Memory: &libvirtxml.DomainMemory{
			Unit:  "MiB",
			Value: 512,
		},
		VCPU: &libvirtxml.DomainVCPU{
			Placement: "static",
			Value:     1,
		},
		CPU: &libvirtxml.DomainCPU{},
		Devices: &libvirtxml.DomainDeviceList{
			Graphics: []libvirtxml.DomainGraphic{
				libvirtxml.DomainGraphic{
					Type:     "spice",
					AutoPort: "yes",
				},
			},
			Channels: []libvirtxml.DomainChannel{
				libvirtxml.DomainChannel{
					Type: "unix",
					Source: &libvirtxml.DomainChardevSource{
						Mode: "bind",
					},
					Target: &libvirtxml.DomainChannelTarget{
						Type: "virtio",
						Name: "org.qemu.guest_agent.0",
					},
				},
			},
			RNGs: []libvirtxml.DomainRNG{
				libvirtxml.DomainRNG{
					Model: "virtio",
					Backend: &libvirtxml.DomainRNGBackend{
						Model: "random",
					},
				},
			},
		},
		Features: &libvirtxml.DomainFeatureList{
			PAE:  &libvirtxml.DomainFeature{},
			ACPI: &libvirtxml.DomainFeature{},
			APIC: &libvirtxml.DomainFeatureAPIC{},
		},
	}

	if v := os.Getenv("TERRAFORM_LIBVIRT_TEST_DOMAIN_TYPE"); v != "" {
		domainDef.Type = v
	} else {
		domainDef.Type = "kvm"
	}

	return domainDef
}

func newDomainDefForConnection(virConn *libvirt.Connect) (libvirtxml.Domain, error) {
	d := newDomainDef()
	caps, err := getHostCapabilities(virConn)
	if err != nil {
		return d, err
	}
	guest, err := getGuestForArchType(caps, d.OS.Type.Arch, d.OS.Type.Type)
	if err != nil {
		return d, err
	}

	d.Devices.Emulator = guest.Arch.Emulator

	canonicalmachine, err := getCanonicalMachineName(caps, d.OS.Type.Arch, d.OS.Type.Type, d.OS.Type.Machine)
	if err != nil {
		return d, err
	}
	d.OS.Type.Machine = canonicalmachine
	return d, nil
}
<commit_msg>Bugfix: let libvirt populate channel source<commit_after>package libvirt

import (
	libvirt "github.com/libvirt/libvirt-go"
	libvirtxml "github.com/libvirt/libvirt-go-xml"
	"os"
)

func newFilesystemDef() libvirtxml.DomainFilesystem {
	return libvirtxml.DomainFilesystem{
		Type:       "mount",  // This is the only type used by qemu/kvm
		AccessMode: "mapped", // A safe default value
		ReadOnly:   &libvirtxml.DomainFilesystemReadOnly{},
	}
}

// Creates a domain definition with the defaults
// the provider uses
func newDomainDef() libvirtxml.Domain {
	domainDef := libvirtxml.Domain{
		OS: &libvirtxml.DomainOS{
			Type: &libvirtxml.DomainOSType{
				Type:    "hvm",
				Arch:    "x86_64",
				Machine: "pc",
			},
		},
		Memory: &libvirtxml.DomainMemory{
			Unit:  "MiB",
			Value: 512,
		},
		VCPU: &libvirtxml.DomainVCPU{
			Placement: "static",
			Value:     1,
		},
		CPU: &libvirtxml.DomainCPU{},
		Devices: &libvirtxml.DomainDeviceList{
			Graphics: []libvirtxml.DomainGraphic{
				libvirtxml.DomainGraphic{
					Type:     "spice",
					AutoPort: "yes",
				},
			},
			Channels: []libvirtxml.DomainChannel{
				libvirtxml.DomainChannel{
					Type: "unix",
					Target: &libvirtxml.DomainChannelTarget{
						Type: "virtio",
						Name: "org.qemu.guest_agent.0",
					},
				},
			},
			RNGs: []libvirtxml.DomainRNG{
				libvirtxml.DomainRNG{
					Model: "virtio",
					Backend: &libvirtxml.DomainRNGBackend{
						Model: "random",
					},
				},
			},
		},
		Features: &libvirtxml.DomainFeatureList{
			PAE:  &libvirtxml.DomainFeature{},
			ACPI: &libvirtxml.DomainFeature{},
			APIC: &libvirtxml.DomainFeatureAPIC{},
		},
	}

	if v := os.Getenv("TERRAFORM_LIBVIRT_TEST_DOMAIN_TYPE"); v != "" {
		domainDef.Type = v
	} else {
		domainDef.Type = "kvm"
	}

	return domainDef
}

func newDomainDefForConnection(virConn *libvirt.Connect) (libvirtxml.Domain, error) {
	d := newDomainDef()
	caps, err := getHostCapabilities(virConn)
	if err != nil {
		return d, err
	}
	guest, err := getGuestForArchType(caps, d.OS.Type.Arch, d.OS.Type.Type)
	if err != nil {
		return d, err
	}

	d.Devices.Emulator = guest.Arch.Emulator

	canonicalmachine, err := getCanonicalMachineName(caps, d.OS.Type.Arch, d.OS.Type.Type, d.OS.Type.Machine)
	if err != nil {
		return d, err
	}
	d.OS.Type.Machine = canonicalmachine
	return d, nil
}
<|endoftext|>