mirror of
https://github.com/hashicorp/packer.git
synced 2026-09-28 02:34:02 -04:00
tooling. Tested on OSX, `Windows, and Linux. Documented command line dependencies. Added acceptance tests (behind testacc flag, since there are dependencies). This option is only implemented for the vmware and hyperv iso builders. It will be implemented for others in later PRs in order to make review easier.
202 lines
4.9 KiB
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)
|
|
}
|