github.com/grahambrereton-form3/tilt@v0.10.18/internal/synclet/synclet.go (about)

     1  package synclet
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"log"
     7  	"strings"
     8  
     9  	"github.com/pkg/errors"
    10  
    11  	"github.com/windmilleng/tilt/internal/build"
    12  	"github.com/windmilleng/tilt/internal/container"
    13  	"github.com/windmilleng/tilt/pkg/logger"
    14  
    15  	"github.com/opentracing/opentracing-go"
    16  
    17  	"github.com/windmilleng/tilt/internal/docker"
    18  	"github.com/windmilleng/tilt/pkg/model"
    19  )
    20  
    21  const Port = 23551
    22  
    23  type Synclet struct {
    24  	dCli docker.Client
    25  }
    26  
    27  func NewSynclet(dCli docker.Client) *Synclet {
    28  	return &Synclet{dCli: dCli}
    29  }
    30  
    31  func (s Synclet) writeFiles(ctx context.Context, containerId container.ID, tarArchive []byte) error {
    32  	span, ctx := opentracing.StartSpanFromContext(ctx, "Synclet-writeFiles")
    33  	defer span.Finish()
    34  
    35  	if tarArchive == nil {
    36  		return nil
    37  	}
    38  
    39  	return s.dCli.CopyToContainerRoot(ctx, containerId.String(), bytes.NewBuffer(tarArchive))
    40  }
    41  
    42  func (s Synclet) rmFiles(ctx context.Context, containerId container.ID, filesToDelete []string) error {
    43  	span, ctx := opentracing.StartSpanFromContext(ctx, "Synclet-rmFiles")
    44  	defer span.Finish()
    45  
    46  	if len(filesToDelete) == 0 {
    47  		return nil
    48  	}
    49  
    50  	cmd := model.Cmd{Argv: append([]string{"rm", "-rf"}, filesToDelete...)}
    51  
    52  	out := bytes.NewBuffer(nil)
    53  	err := s.dCli.ExecInContainer(ctx, containerId, cmd, out)
    54  	if err != nil {
    55  		dockerExitErr, ok := err.(docker.ExitError)
    56  		if ok {
    57  			return errors.Wrapf(err, "Error deleting files. exit code %d, output '%s'", dockerExitErr.ExitCode, out.String())
    58  		}
    59  		return errors.Wrap(err, "Error deleting files")
    60  	}
    61  	return nil
    62  }
    63  
    64  func (s Synclet) execCmds(ctx context.Context, containerId container.ID, cmds []model.Cmd) error {
    65  	span, ctx := opentracing.StartSpanFromContext(ctx, "Synclet-execCommands")
    66  	defer span.Finish()
    67  
    68  	for i, c := range cmds {
    69  		// TODO: instrument this
    70  		log.Printf("[CMD %d/%d] %s", i+1, len(cmds), strings.Join(c.Argv, " "))
    71  		// TODO(matt) - plumb PipelineState through
    72  		l := logger.Get(ctx)
    73  		err := s.dCli.ExecInContainer(ctx, containerId, c, l.Writer(logger.InfoLvl))
    74  		if err != nil {
    75  			return build.WrapContainerExecError(err, containerId, c)
    76  		}
    77  	}
    78  	return nil
    79  }
    80  
    81  func (s Synclet) restartContainer(ctx context.Context, containerId container.ID) error {
    82  	span, ctx := opentracing.StartSpanFromContext(ctx, "Synclet-restartContainer")
    83  	defer span.Finish()
    84  
    85  	return s.dCli.ContainerRestartNoWait(ctx, containerId.String())
    86  }
    87  
    88  func (s Synclet) UpdateContainer(
    89  	ctx context.Context,
    90  	containerId container.ID,
    91  	tarArchive []byte,
    92  	filesToDelete []string,
    93  	commands []model.Cmd,
    94  	hotReload bool) error {
    95  
    96  	span, ctx := opentracing.StartSpanFromContext(ctx, "Synclet-UpdateContainer")
    97  	defer span.Finish()
    98  
    99  	err := s.rmFiles(ctx, containerId, filesToDelete)
   100  	if err != nil {
   101  		return errors.Wrapf(err, "error removing files while updating container %s",
   102  			containerId.ShortStr())
   103  	}
   104  
   105  	err = s.writeFiles(ctx, containerId, tarArchive)
   106  	if err != nil {
   107  		return errors.Wrapf(err, "error writing files while updating container %s",
   108  			containerId.ShortStr())
   109  	}
   110  
   111  	err = s.execCmds(ctx, containerId, commands)
   112  	if err != nil {
   113  		return errors.Wrapf(err, "error exec'ing commands while updating container %s",
   114  			containerId.ShortStr())
   115  	}
   116  
   117  	if !hotReload {
   118  		err = s.restartContainer(ctx, containerId)
   119  		if err != nil {
   120  			return errors.Wrapf(err, "error restarting container %s",
   121  				containerId.ShortStr())
   122  		}
   123  	}
   124  
   125  	return nil
   126  }