You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: setupdomain.go
    path of file: ./repos/upspin/cmd/upspin
    
    the code of the file until where you have to start completion: // Copyright 2016 The Upspin 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 (
	"bytes"
	"crypto/sha256"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"text/template"

	yaml "gopkg.in/yaml.v2"

	"upspin.io/config"
	"upspin.io/key/keygen"
	"upspin.io/subcmd"
	"upspin.io/upspin"
)

// This file implements the initial configuration for a new domain.

func (s *State) setupdomain(args ...string) {
	const (
		help = `
Setupdomain is the first step in setting up an upspinserver or Upspin
Kubernetes cluster. If setting up an upspinserver, the next steps are
'setupstorage' (optionally) and 'setupserver'.

It generates keys and config files for Upspin server users, placing them in
$where/$domain (the values of the -where and -domain flags substitute for
$where and $domain respectively) and generates a signature that proves that the
calling Upspin user has control over domain.

If the -cluster flag is specified, keys for upspin-dir@domain and
upspin-store@domain are created instead. This flag should be used when setting
up a domain that will run its directory and store servers separately, requiring
separate users to adminster each one. When -cluster is not specified, keys for
a single user (upspin@domain) are generated.

If any state exists at the given location (-where) then the command aborts.
`
	)
	fs := flag.NewFlagSet("setupdomain", flag.ExitOnError)
	whereFlag := fs.String("where", filepath.Join(config.Home(), "upspin", "deploy"), "`directory` to store private configuration files")
	domain := fs.String("domain", "", "domain `name` for this Upspin installation")
	project := fs.String("project", "", "GCP `project` name")
	curveName := fs.String("curve", "p256", "cryptographic curve `name`: p256, p384, or p521")
	seed := fs.String("secretseed", "", "the seed containing a 128 bit secret in proquint format or a file that contains it")
	putUsers := fs.Bool("put-users", false, "put server users to the key server")
	cluster := fs.Bool("cluster", false, "generate keys for upspin-dir@domain and upspin-store@domain (default is upspin@domain only)")
	s.ParseFlags(fs, args, help, "setupdomain [-where=$HOME/upspin/deploy] [-cluster] -domain=<name>")
	if *whereFlag == "" {
		s.Failf("the -where flag must not be empty")
		usageAndExit(fs)
	}
	if *domain == "" {
		s.Failf("the -domain flag must be provided")
		usageAndExit(fs)
	}
	switch *curveName {
	case "p256", "p384",
    
func (s *State) setupdomain(args ...string) {
	const (
		help = `
Setupdomain is the first step in setting up an upspinserver or Upspin
Kubernetes cluster. If setting up an upspinserver, the next steps are
'setupstorage' (optionally) and 'setupserver'.

It generates keys and config files for Upspin server users, placing them in
$where/$domain (the values of the -where and -domain flags substitute for
$where and $domain respectively) and generates a signature that proves that the
calling Upspin user has control over domain.

If the -cluster flag is specified, keys for upspin-dir@domain and
upspin-store@domain are created instead. This flag should be used when setting
up a domain that will run its directory and store servers separately, requiring
separate users to adminster each one. When -cluster is not specified, keys for
a single user (upspin@domain) are generated.

If any state exists at the given location (-where) then the command aborts.
`
	)
	fs := flag.NewFlagSet("setupdomain", flag.ExitOnError)
	whereFlag := fs.String("where", filepath.Join(config.Home(), "upspin", "deploy"), "`directory` to store private configuration files")
	domain := fs.String("domain", "", "domain `name` for this Upspin installation")
	project := fs.String("project", "", "GCP `project` name")
	curveName := fs.String("curve", "p256", "cryptographic curve `name`: p256, p384, or p521")
	seed := fs.String("secretseed", "", "the seed containing a 128 bit secret in proquint format or a file that contains it")
	putUsers := fs.Bool("put-users", false, "put server users to the key server")
	cluster := fs.Bool("cluster", false, "generate keys for upspin-dir@domain and upspin-store@domain (default is upspin@domain only)")
	s.ParseFlags(fs, args, help, "setupdomain [-where=$HOME/upspin/deploy] [-cluster] -domain=<name>")
	if *whereFlag == "" {
		s.Failf("the -where flag must not be empty")
		usageAndExit(fs)
	}
	if *domain == "" {
		s.Failf("the -domain flag must be provided")
		usageAndExit(fs)
	}
	switch *curveName {
	case "p256", "p384", "p521":
		// OK
	default:
		s.Exitf("no such curve %q", *curveName)
	}

	where := subcmd.Tilde(*whereFlag)

	if !*cluster {
		if *putUsers {
			s.Exitf("the -put-users flag requires -cluster")
		}
		s.setuphost(where, *domain, *curveName, *seed)
		return
	}
	if *project == "" {
		s.Failf("the -project flag must be provided")
		usageAndExit(fs)
	}

	var (
		baseDir         = filepath.Join(where, *domain)
		dirServerPath   = filepath.Join(baseDir, "dirserver")
		storeServerPath = filepath.Join(baseDir, "storeserver")
		dirConfig       = filepath.Join(dirServerPath, "config")
		storeConfig     = filepath.Join(storeServerPath, "config")
	)

	if *putUsers {
		dirFile, dirUser, err := writeUserFile(dirConfig)
		if err != nil {
			s.Exit(err)
		}
		storeFile, storeUser, err := writeUserFile(storeConfig)
		if err != nil {
			s.Exit(err)
		}
		s.user("-put", "-in", dirFile)
		os.Remove(dirFile)
		s.user("-put", "-in", storeFile)
		os.Remove(storeFile)
		fmt.Fprintf(s.Stderr, "Successfully put %q and %q to the key server.\n", dirUser, storeUser)
		return
	}

	s.ShouldNotExist(dirServerPath)
	s.ShouldNotExist(storeServerPath)
	s.MkdirAllLocal(dirServerPath)
	s.MkdirAllLocal(storeServerPath)

	// Generate keys for the dirserver and the storeserver.
	var noProquint string
	dirCurve := *curveName
	dirPublic, dirPrivate, dirProquint, err := s.createKeys(*curveName, noProquint)
	if err != nil {
		s.Exit(err)
	}
	storeCurve := *curveName
	storePublic, storePrivate, storeProquint, err := s.createKeys(*curveName, noProquint)
	if err != nil {
		s.Exit(err)
	}
	err = keygen.SaveKeys(dirServerPath, false, dirPublic, dirPrivate, dirProquint)
	if err != nil {
		s.Exit(err)
	}
	err = keygen.SaveKeys(storeServerPath, false, storePublic, storePrivate, storeProquint)
	if err != nil {
		s.Exit(err)
	}

	// Generate config files for those users.
	dirEndpoint := upspin.Endpoint{
		Transport: upspin.Remote,
		NetAddr:   upspin.NetAddr("dir." + *domain + ":443"),
	}
	storeEndpoint := upspin.Endpoint{
		Transport: upspin.Remote,
		NetAddr:   upspin.NetAddr("store." + *domain + ":443"),
	}
	var dirBody bytes.Buffer
	if err := configTemplate.Execute(&dirBody, configData{
		UserName:  upspin.UserName("upspin-dir@" + *domain),
		Store:     &storeEndpoint,
		Dir:       &dirEndpoint,
		SecretDir: dirServerPath,
		Packing:   "ee",
	}); err != nil {
		s.Exit(err)
	}
	if err := ioutil.WriteFile(dirConfig, dirBody.Bytes(), 0644); err != nil {
		s.Exit(err)
	}
	var storeBody bytes.Buffer
	if err := configTemplate.Execute(&storeBody, configData{
		UserName:  upspin.UserName("upspin-store@" + *domain),
		Store:     &storeEndpoint,
		Dir:       &dirEndpoint,
		SecretDir: storeServerPath,
		Packing:   "plain",
	}); err != nil {
		s.Exit(err)
	}
	if err := ioutil.WriteFile(storeConfig, storeBody.Bytes(), 0644); err != nil {
		s.Exit(err)
	}

	// Generate signature.
	msg := "upspin-domain:" + *domain + "-" + string(s.Config.UserName())
	hash := sha256.Sum256([]byte(msg))
	sig, err := s.Config.Factotum().Sign(hash[:])
	if err != nil {
		s.Exit(err)
	}

	err = setupDomainTemplate.Execute(s.Stdout, setupDomainData{
		Dir:       baseDir,
		Where:     where,
		Domain:    *domain,
		Project:   *project,
		UserName:  s.Config.UserName(),
		Signature: fmt.Sprintf("%x-%x", sig.R, sig.S),

		DirCurve:        dirCurve,
		StoreCurve:      storeCurve,
		DirProquint:     dirProquint,
		StoreProquint:   storeProquint,
		DirServerPath:   dirServerPath,
		StoreServerPath: storeServerPath,
	})
	if err != nil {
		s.Exit(err)
	}
}