Do not format at each write but use a Writer instead (build)

This commit is contained in:
Guillaume J. Charmes 2013-12-02 11:43:41 -08:00
parent 8cc524996a
commit de4429f70d
No known key found for this signature in database
GPG Key ID: B33E4642CB6E3FF3
2 changed files with 63 additions and 35 deletions

15
api.go
View File

@ -960,11 +960,20 @@ func postBuild(srv *Server, version float64, w http.ResponseWriter, r *http.Requ
return err
}
if version > 1.6 {
if version >= 1.8 {
w.Header().Set("Content-Type", "application/json")
}
sf := utils.NewStreamFormatter(version > 1.6)
b := NewBuildFile(srv, utils.NewWriteFlusher(w), !suppressOutput, !noCache, rm, sf)
sf := utils.NewStreamFormatter(version >= 1.8)
b := NewBuildFile(srv,
&StdoutFormater{
Writer: utils.NewWriteFlusher(w),
StreamFormatter: sf,
},
&StderrFormater{
Writer: utils.NewWriteFlusher(w),
StreamFormatter: sf,
},
!suppressOutput, !noCache, rm, utils.NewWriteFlusher(w), sf)
id, err := b.Build(context)
if err != nil {
if sf.Used() {

View File

@ -36,15 +36,19 @@ type buildFile struct {
tmpContainers map[string]struct{}
tmpImages map[string]struct{}
out io.Writer
sf *utils.StreamFormatter
outStream io.Writer
errStream io.Writer
// Deprecated, original writer used for ImagePull. To be removed.
outOld io.Writer
sf *utils.StreamFormatter
}
func (b *buildFile) clearTmp(containers map[string]struct{}) {
for c := range containers {
tmp := b.runtime.Get(c)
b.runtime.Destroy(tmp)
fmt.Fprintf(b.out, "Removing intermediate container %s\n", utils.TruncateID(c))
fmt.Fprintf(b.outStream, "Removing intermediate container %s\n", utils.TruncateID(c))
}
}
@ -53,7 +57,7 @@ func (b *buildFile) CmdFrom(name string) error {
if err != nil {
if b.runtime.graph.IsNotExist(err) {
remote, tag := utils.ParseRepositoryTag(name)
if err := b.srv.ImagePull(remote, tag, b.out, b.sf, nil, nil, true); err != nil {
if err := b.srv.ImagePull(remote, tag, b.outOld, b.sf, nil, nil, true); err != nil {
return err
}
image, err = b.runtime.repositories.LookupImage(name)
@ -101,11 +105,7 @@ func (b *buildFile) CmdRun(args string) error {
if cache, err := b.srv.ImageGetCached(b.image, b.config); err != nil {
return err
} else if cache != nil {
if b.sf.Used() {
b.out.Write(b.sf.FormatStatus("", " ---> Using cache"))
} else {
fmt.Fprintf(b.out, " ---> Using cache\n")
}
fmt.Fprintf(b.outStream, " ---> Using cache\n")
utils.Debugf("[BUILDER] Use cached version")
b.image = cache.ID
return nil
@ -369,6 +369,34 @@ func (b *buildFile) CmdAdd(args string) error {
return nil
}
type StdoutFormater struct {
io.Writer
*utils.StreamFormatter
}
func (sf *StdoutFormater) Write(buf []byte) (int, error) {
formattedBuf := sf.StreamFormatter.FormatStatus("", "%s", string(buf))
n, err := sf.Writer.Write(formattedBuf)
if n != len(formattedBuf) {
return n, io.ErrShortWrite
}
return len(buf), err
}
type StderrFormater struct {
io.Writer
*utils.StreamFormatter
}
func (sf *StderrFormater) Write(buf []byte) (int, error) {
formattedBuf := sf.StreamFormatter.FormatStatus("", "%s", "\033[91m"+string(buf)+"\033[0m")
n, err := sf.Writer.Write(formattedBuf)
if n != len(formattedBuf) {
return n, io.ErrShortWrite
}
return len(buf), err
}
func (b *buildFile) run() (string, error) {
if b.image == "" {
return "", fmt.Errorf("Please provide a source image with `from` prior to run")
@ -381,11 +409,8 @@ func (b *buildFile) run() (string, error) {
return "", err
}
b.tmpContainers[c.ID] = struct{}{}
if b.sf.Used() {
b.out.Write(b.sf.FormatStatus("", " ---> Running in %s", utils.TruncateID(c.ID)))
} else {
fmt.Fprintf(b.out, " ---> Running in %s\n", utils.TruncateID(c.ID))
}
fmt.Fprintf(b.outStream, " ---> Running in %s\n", utils.TruncateID(c.ID))
// override the entry point that may have been picked up from the base image
c.Path = b.config.Cmd[0]
c.Args = b.config.Cmd[1:]
@ -394,7 +419,7 @@ func (b *buildFile) run() (string, error) {
if b.verbose {
errCh = utils.Go(func() error {
return <-c.Attach(nil, nil, b.out, b.out)
return <-c.Attach(nil, nil, b.outStream, b.errStream)
})
}
@ -436,11 +461,7 @@ func (b *buildFile) commit(id string, autoCmd []string, comment string) error {
if cache, err := b.srv.ImageGetCached(b.image, b.config); err != nil {
return err
} else if cache != nil {
if b.sf.Used() {
b.out.Write(b.sf.FormatStatus("", " ---> Using cache"))
} else {
fmt.Fprintf(b.out, " ---> Using cache\n")
}
fmt.Fprintf(b.outStream, " ---> Using cache\n")
utils.Debugf("[BUILDER] Use cached version")
b.image = cache.ID
return nil
@ -454,14 +475,10 @@ func (b *buildFile) commit(id string, autoCmd []string, comment string) error {
return err
}
for _, warning := range warnings {
fmt.Fprintf(b.out, " ---> [Warning] %s\n", warning)
fmt.Fprintf(b.outStream, " ---> [Warning] %s\n", warning)
}
b.tmpContainers[container.ID] = struct{}{}
if b.sf.Used() {
b.out.Write(b.sf.FormatStatus("", " ---> Running in %s", utils.TruncateID(container.ID)))
} else {
fmt.Fprintf(b.out, " ---> Running in %s\n", utils.TruncateID(container.ID))
}
fmt.Fprintf(b.outStream, " ---> Running in %s\n", utils.TruncateID(container.ID))
id = container.ID
if err := container.EnsureMounted(); err != nil {
return err
@ -527,22 +544,22 @@ func (b *buildFile) Build(context io.Reader) (string, error) {
method, exists := reflect.TypeOf(b).MethodByName("Cmd" + strings.ToUpper(instruction[:1]) + strings.ToLower(instruction[1:]))
if !exists {
b.out.Write(b.sf.FormatStatus("", "# Skipping unknown instruction %s", strings.ToUpper(instruction)))
fmt.Fprintf(b.errStream, "# Skipping unknown instruction %s\n", strings.ToUpper(instruction))
continue
}
stepN += 1
b.out.Write(b.sf.FormatStatus("", "Step %d : %s %s", stepN, strings.ToUpper(instruction), arguments))
fmt.Fprintf(b.outStream, "Step %d : %s %s\n", stepN, strings.ToUpper(instruction), arguments)
ret := method.Func.Call([]reflect.Value{reflect.ValueOf(b), reflect.ValueOf(arguments)})[0].Interface()
if ret != nil {
return "", ret.(error)
}
b.out.Write(b.sf.FormatStatus("", " ---> %s", utils.TruncateID(b.image)))
fmt.Fprintf(b.outStream, " ---> %s\n", utils.TruncateID(b.image))
}
if b.image != "" {
b.out.Write(b.sf.FormatStatus("", "Successfully built %s", utils.TruncateID(b.image)))
fmt.Fprintf(b.outStream, "Successfully built %s\n", utils.TruncateID(b.image))
if b.rm {
b.clearTmp(b.tmpContainers)
}
@ -551,17 +568,19 @@ func (b *buildFile) Build(context io.Reader) (string, error) {
return "", fmt.Errorf("An error occurred during the build\n")
}
func NewBuildFile(srv *Server, out io.Writer, verbose, utilizeCache, rm bool, sf *utils.StreamFormatter) BuildFile {
func NewBuildFile(srv *Server, outStream, errStream io.Writer, verbose, utilizeCache, rm bool, outOld io.Writer, sf *utils.StreamFormatter) BuildFile {
return &buildFile{
runtime: srv.runtime,
srv: srv,
config: &Config{},
out: out,
outStream: outStream,
errStream: errStream,
tmpContainers: make(map[string]struct{}),
tmpImages: make(map[string]struct{}),
verbose: verbose,
utilizeCache: utilizeCache,
rm: rm,
sf: sf,
outOld: outOld,
}
}