|  |  | @ -13,6 +13,14 @@ import ( | 
			
		
	
		
		
			
				
					
					|  |  |  | 	"golang.org/x/term" |  |  |  | 	"golang.org/x/term" | 
			
		
	
		
		
			
				
					
					|  |  |  | ) |  |  |  | ) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const helpMessage = ` | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | Available commads are: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   reload   reloads the context and build it. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   rollback re-runs the interactive container with initial rootfs contents. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   exit     exits monitor. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   help     shows this message. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | ` | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | // RunMonitor provides an interactive session for running and managing containers via specified IO.
 |  |  |  | // RunMonitor provides an interactive session for running and managing containers via specified IO.
 | 
			
		
	
		
		
			
				
					
					|  |  |  | func RunMonitor(ctx context.Context, containerConfig build.ContainerConfig, reloadFunc func(context.Context) (*build.ResultContext, error), stdin io.ReadCloser, stdout, stderr io.WriteCloser) error { |  |  |  | func RunMonitor(ctx context.Context, containerConfig build.ContainerConfig, reloadFunc func(context.Context) (*build.ResultContext, error), stdin io.ReadCloser, stdout, stderr io.WriteCloser) error { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	monitorIn, monitorOut := ioSetPipe() |  |  |  | 	monitorIn, monitorOut := ioSetPipe() | 
			
		
	
	
		
		
			
				
					|  |  | @ -34,11 +42,18 @@ func RunMonitor(ctx context.Context, containerConfig build.ContainerConfig, relo | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	m := &monitor{ |  |  |  | 	m := &monitor{ | 
			
		
	
		
		
			
				
					
					|  |  |  | 		invokeIO: newIOForwarder(containerIn), |  |  |  | 		invokeIO: newIOForwarder(containerIn), | 
			
		
	
		
		
			
				
					
					|  |  |  | 		muxIO:    newMuxIO(ioSetIn{stdin, stdout, stderr}, []ioSetOutContext{monitorOutCtx, containerOutCtx}, 1, "Switched IO\n"), |  |  |  | 		muxIO: newMuxIO(ioSetIn{stdin, stdout, stderr}, []ioSetOutContext{monitorOutCtx, containerOutCtx}, 1, func(prev int, res int) string { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			if prev == 0 && res == 0 { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				// No toggle happened because container I/O isn't enabled.
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				return "No running interactive containers. You can start one by issuing rollback command\n" | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			return "Switched IO\n" | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		}), | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	// Start container automatically
 |  |  |  | 	// Start container automatically
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	go func() { |  |  |  | 	go func() { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		fmt.Fprintf(stdout, "Launching interactive container. Press Ctrl-a-c to switch to monitor console\n") | 
			
		
	
		
		
			
				
					
					|  |  |  | 		m.rollback(ctx, containerConfig) |  |  |  | 		m.rollback(ctx, containerConfig) | 
			
		
	
		
		
			
				
					
					|  |  |  | 	}() |  |  |  | 	}() | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -73,13 +88,18 @@ func RunMonitor(ctx context.Context, containerConfig build.ContainerConfig, relo | 
			
		
	
		
		
			
				
					
					|  |  |  | 						// rollback the running container with the new result
 |  |  |  | 						// rollback the running container with the new result
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 						containerConfig.ResultCtx = res |  |  |  | 						containerConfig.ResultCtx = res | 
			
		
	
		
		
			
				
					
					|  |  |  | 						m.rollback(ctx, containerConfig) |  |  |  | 						m.rollback(ctx, containerConfig) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 						fmt.Fprint(stdout, "Interactive container was restarted. Press Ctrl-a-c to switch to the new container\n") | 
			
		
	
		
		
			
				
					
					|  |  |  | 					} |  |  |  | 					} | 
			
		
	
		
		
			
				
					
					|  |  |  | 				case "rollback": |  |  |  | 				case "rollback": | 
			
		
	
		
		
			
				
					
					|  |  |  | 					m.rollback(ctx, containerConfig) |  |  |  | 					m.rollback(ctx, containerConfig) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 					fmt.Fprint(stdout, "Interactive container was restarted. Press Ctrl-a-c to switch to the new container\n") | 
			
		
	
		
		
			
				
					
					|  |  |  | 				case "exit": |  |  |  | 				case "exit": | 
			
		
	
		
		
			
				
					
					|  |  |  | 					return |  |  |  | 					return | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				case "help": | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 					fmt.Fprint(stdout, helpMessage) | 
			
		
	
		
		
			
				
					
					|  |  |  | 				default: |  |  |  | 				default: | 
			
		
	
		
		
			
				
					
					|  |  |  | 					fmt.Printf("unknown command: %q\n", l) |  |  |  | 					fmt.Printf("unknown command: %q\n", l) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 					fmt.Fprint(stdout, helpMessage) | 
			
		
	
		
		
			
				
					
					|  |  |  | 				} |  |  |  | 				} | 
			
		
	
		
		
			
				
					
					|  |  |  | 			} |  |  |  | 			} | 
			
		
	
		
		
			
				
					
					|  |  |  | 		}() |  |  |  | 		}() | 
			
		
	
	
		
		
			
				
					|  |  | @ -227,7 +247,7 @@ type ioSetOutContext struct { | 
			
		
	
		
		
			
				
					
					|  |  |  | // newMuxIO forwards IO stream to/from "in" and "outs".
 |  |  |  | // newMuxIO forwards IO stream to/from "in" and "outs".
 | 
			
		
	
		
		
			
				
					
					|  |  |  | // "outs" are closed automatically when "in" reaches EOF.
 |  |  |  | // "outs" are closed automatically when "in" reaches EOF.
 | 
			
		
	
		
		
			
				
					
					|  |  |  | // "in" doesn't closed automatically so the caller needs to explicitly close it.
 |  |  |  | // "in" doesn't closed automatically so the caller needs to explicitly close it.
 | 
			
		
	
		
		
			
				
					
					|  |  |  | func newMuxIO(in ioSetIn, out []ioSetOutContext, initIdx int, toggleMessage string) *muxIO { |  |  |  | func newMuxIO(in ioSetIn, out []ioSetOutContext, initIdx int, toggleMessage func(prev int, res int) string) *muxIO { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	m := &muxIO{ |  |  |  | 	m := &muxIO{ | 
			
		
	
		
		
			
				
					
					|  |  |  | 		enabled:       make(map[int]struct{}), |  |  |  | 		enabled:       make(map[int]struct{}), | 
			
		
	
		
		
			
				
					
					|  |  |  | 		in:            in, |  |  |  | 		in:            in, | 
			
		
	
	
		
		
			
				
					|  |  | @ -327,7 +347,7 @@ type muxIO struct { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	in            ioSetIn |  |  |  | 	in            ioSetIn | 
			
		
	
		
		
			
				
					
					|  |  |  | 	out           []ioSetOutContext |  |  |  | 	out           []ioSetOutContext | 
			
		
	
		
		
			
				
					
					|  |  |  | 	closedCh      chan struct{} |  |  |  | 	closedCh      chan struct{} | 
			
		
	
		
		
			
				
					
					|  |  |  | 	toggleMessage string |  |  |  | 	toggleMessage func(prev int, res int) string | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | func (m *muxIO) waitClosed() { |  |  |  | func (m *muxIO) waitClosed() { | 
			
		
	
	
		
		
			
				
					|  |  | @ -357,6 +377,7 @@ func (m *muxIO) toggleIO() { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	if m.out[m.cur].disableHook != nil { |  |  |  | 	if m.out[m.cur].disableHook != nil { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		m.out[m.cur].disableHook() |  |  |  | 		m.out[m.cur].disableHook() | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	prev := m.cur | 
			
		
	
		
		
			
				
					
					|  |  |  | 	for { |  |  |  | 	for { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		if m.cur+1 >= m.maxCur { |  |  |  | 		if m.cur+1 >= m.maxCur { | 
			
		
	
		
		
			
				
					
					|  |  |  | 			m.cur = 0 |  |  |  | 			m.cur = 0 | 
			
		
	
	
		
		
			
				
					|  |  | @ -368,10 +389,11 @@ func (m *muxIO) toggleIO() { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  | 		break |  |  |  | 		break | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	res := m.cur | 
			
		
	
		
		
			
				
					
					|  |  |  | 	if m.out[m.cur].enableHook != nil { |  |  |  | 	if m.out[m.cur].enableHook != nil { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		m.out[m.cur].enableHook() |  |  |  | 		m.out[m.cur].enableHook() | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  | 	fmt.Fprintf(m.in.stdout, m.toggleMessage) |  |  |  | 	fmt.Fprint(m.in.stdout, m.toggleMessage(prev, res)) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | func traceReader(r io.ReadCloser, f func(rune) (bool, error)) io.ReadCloser { |  |  |  | func traceReader(r io.ReadCloser, f func(rune) (bool, error)) io.ReadCloser { | 
			
		
	
	
		
		
			
				
					|  |  | 
 |