packer-cn/common/step_create_cdrom.go

202 lines
4.9 KiB
Go

package common
import (
"context"
"fmt"
"io"
"log"
"os"
"os/exec"
"path/filepath"
"runtime"
"github.com/hashicorp/packer/helper/builder/localexec"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/packer/tmp"
)
// StepCreateCD will create a CD disk with the given files.
type StepCreateCD struct {
// Files can be either files or directories. Any files provided here will
// be written to the root of the CD. Directories will be written to the
// root of the CD as well, but will retain their subdirectory structure.
Files []string
Label string
CDPath string
filesAdded map[string]bool
}
func (s *StepCreateCD) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
if len(s.Files) == 0 {
log.Println("No CD files specified. CD disk will not be made.")
return multistep.ActionContinue
}
ui := state.Get("ui").(packer.Ui)
ui.Say("Creating CD disk...")
if s.Label == "" {
s.Label = "packer"
} else {
log.Printf("CD label is set to %s", s.Label)
}
// Track what files are added. Used for testing step.
s.filesAdded = make(map[string]bool)
// Create a temporary file to be our CD drive
CDF, err := tmp.File("packer*.iso")
// Set the path so we can remove it later
CDPath := CDF.Name()
CDF.Close()
os.Remove(CDPath)
if err != nil {
state.Put("error",
fmt.Errorf("Error creating temporary file for CD: %s", err))
return multistep.ActionHalt
}
log.Printf("CD path: %s", CDPath)
s.CDPath = CDPath
// Consolidate all files provided into a single directory to become our
// "root" directory.
rootFolder, err := tmp.Dir("packer_to_cdrom")
if err != nil {
state.Put("error",
fmt.Errorf("Error creating temporary file for CD: %s", err))
return multistep.ActionHalt
}
for _, toAdd := range s.Files {
err = s.AddFile(rootFolder, toAdd)
if err != nil {
state.Put("error",
fmt.Errorf("Error creating temporary file for CD: %s", err))
return multistep.ActionHalt
}
}
cmd := retrieveCommandForOS(s.Label, rootFolder, CDPath)
err = localexec.RunAndStream(cmd, ui, []string{})
if err != nil {
state.Put("error", err)
return multistep.ActionHalt
}
ui.Message("Done copying paths from CD_dirs")
// Set the path to the CD so it can be used later
state.Put("cd_path", CDPath)
if err != nil {
state.Put("error", err)
return multistep.ActionHalt
}
return multistep.ActionContinue
}
func (s *StepCreateCD) Cleanup(multistep.StateBag) {
if s.CDPath != "" {
log.Printf("Deleting CD disk: %s", s.CDPath)
os.Remove(s.CDPath)
}
}
func retrieveCommandForOS(label string, source string, dest string) *exec.Cmd {
switch runtime.GOOS {
case "windows":
cmd := exec.Command("oscdimg")
args := []string{"-j1", "-o", "-m", "-l" + label, source, dest}
cmd.Args = append(cmd.Args, args...)
return cmd
case "darwin":
cmd := exec.Command("hdiutil")
args := []string{"makehybrid", "-o", dest, "-hfs",
"-joliet", "-iso", "-default-volume-name", label, source}
cmd.Args = append(cmd.Args, args...)
return cmd
default:
cmd := exec.Command("mkisofs")
args := []string{"-joliet", "-volid", label, "-o", dest, source}
cmd.Args = append(cmd.Args, args...)
return cmd
}
}
func (s *StepCreateCD) AddFile(dst, src string) error {
finfo, err := os.Stat(src)
if err != nil {
return fmt.Errorf("Error adding path to CD: %s", err)
}
// add a file
if !finfo.IsDir() {
inputF, err := os.Open(src)
if err != nil {
return err
}
defer inputF.Close()
// Create a new file in the root directory
dest, err := os.Create(filepath.Join(dst, finfo.Name()))
if err != nil {
return fmt.Errorf("Error opening file for copy %s to CD root", src)
}
defer dest.Close()
nBytes, err := io.Copy(dest, inputF)
if err != nil {
return fmt.Errorf("Error copying %s to CD root", src)
}
s.filesAdded[src] = true
log.Printf("Wrote %d bytes to %s", nBytes, finfo.Name())
return err
}
// Add a directory and its subdirectories
visit := func(pathname string, fi os.FileInfo, err error) error {
if err != nil {
return err
}
// add a file
if !fi.IsDir() {
inputF, err := os.Open(pathname)
if err != nil {
return err
}
defer inputF.Close()
fileDst, err := os.Create(filepath.Join(dst, pathname))
if err != nil {
return fmt.Errorf("Error opening file %s on CD", src)
}
defer fileDst.Close()
nBytes, err := io.Copy(fileDst, inputF)
if err != nil {
return fmt.Errorf("Error copying %s to CD", src)
}
s.filesAdded[pathname] = true
log.Printf("Wrote %d bytes to %s", nBytes, pathname)
return err
}
if fi.Mode().IsDir() {
// create the directory on the CD, continue walk.
err := os.Mkdir(filepath.Join(dst, pathname), fi.Mode())
if err != nil {
err = fmt.Errorf("error creating new directory %s: %s",
filepath.Join(dst, pathname), err)
}
return err
}
return err
}
return filepath.Walk(src, visit)
}