Browse code

Create a subpackage for utils

Guillaume J. Charmes authored on 2013/05/15 07:37:35
Showing 22 changed files
... ...
@@ -4,6 +4,7 @@ import (
4 4
 	"encoding/json"
5 5
 	"fmt"
6 6
 	"github.com/dotcloud/docker/auth"
7
+	"github.com/dotcloud/docker/utils"
7 8
 	"github.com/gorilla/mux"
8 9
 	"github.com/shin-/cookiejar"
9 10
 	"io"
... ...
@@ -116,7 +117,7 @@ func getContainersExport(srv *Server, w http.ResponseWriter, r *http.Request, va
116 116
 	name := vars["name"]
117 117
 
118 118
 	if err := srv.ContainerExport(name, w); err != nil {
119
-		Debugf("%s", err.Error())
119
+		utils.Debugf("%s", err.Error())
120 120
 		return err
121 121
 	}
122 122
 	return nil
... ...
@@ -239,7 +240,7 @@ func postCommit(srv *Server, w http.ResponseWriter, r *http.Request, vars map[st
239 239
 	}
240 240
 	config := &Config{}
241 241
 	if err := json.NewDecoder(r.Body).Decode(config); err != nil {
242
-		Debugf("%s", err.Error())
242
+		utils.Debugf("%s", err.Error())
243 243
 	}
244 244
 	repo := r.Form.Get("repo")
245 245
 	tag := r.Form.Get("tag")
... ...
@@ -602,20 +603,20 @@ func ListenAndServe(addr string, srv *Server, logging bool) error {
602 602
 
603 603
 	for method, routes := range m {
604 604
 		for route, fct := range routes {
605
-			Debugf("Registering %s, %s", method, route)
605
+			utils.Debugf("Registering %s, %s", method, route)
606 606
 			// NOTE: scope issue, make sure the variables are local and won't be changed
607 607
 			localRoute := route
608 608
 			localMethod := method
609 609
 			localFct := fct
610 610
 			r.Path(localRoute).Methods(localMethod).HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
611
-				Debugf("Calling %s %s", localMethod, localRoute)
611
+				utils.Debugf("Calling %s %s", localMethod, localRoute)
612 612
 				if logging {
613 613
 					log.Println(r.Method, r.RequestURI)
614 614
 				}
615 615
 				if strings.Contains(r.Header.Get("User-Agent"), "Docker-Client/") {
616 616
 					userAgent := strings.Split(r.Header.Get("User-Agent"), "/")
617 617
 					if len(userAgent) == 2 && userAgent[1] != VERSION {
618
-						Debugf("Warning: client and server don't have the same version (client: %s, server: %s)", userAgent[1], VERSION)
618
+						utils.Debugf("Warning: client and server don't have the same version (client: %s, server: %s)", userAgent[1], VERSION)
619 619
 					}
620 620
 				}
621 621
 				if err := localFct(srv, w, r, mux.Vars(r)); err != nil {
... ...
@@ -811,7 +811,7 @@ func TestPostContainersCreate(t *testing.T) {
811 811
 
812 812
 	if _, err := os.Stat(path.Join(container.rwPath(), "test")); err != nil {
813 813
 		if os.IsNotExist(err) {
814
-			Debugf("Err: %s", err)
814
+			utils.Debugf("Err: %s", err)
815 815
 			t.Fatalf("The test file has not been created")
816 816
 		}
817 817
 		t.Fatal(err)
... ...
@@ -4,6 +4,7 @@ import (
4 4
 	"bufio"
5 5
 	"encoding/json"
6 6
 	"fmt"
7
+	"github.com/dotcloud/docker/utils"
7 8
 	"io"
8 9
 	"os"
9 10
 	"path"
... ...
@@ -161,11 +162,11 @@ func (builder *Builder) clearTmp(containers, images map[string]struct{}) {
161 161
 	for c := range containers {
162 162
 		tmp := builder.runtime.Get(c)
163 163
 		builder.runtime.Destroy(tmp)
164
-		Debugf("Removing container %s", c)
164
+		utils.Debugf("Removing container %s", c)
165 165
 	}
166 166
 	for i := range images {
167 167
 		builder.runtime.graph.Delete(i)
168
-		Debugf("Removing image %s", i)
168
+		utils.Debugf("Removing image %s", i)
169 169
 	}
170 170
 }
171 171
 
... ...
@@ -286,7 +287,7 @@ func (builder *Builder) Build(dockerfile io.Reader, stdout io.Writer) (*Image, e
286 286
 				break
287 287
 			}
288 288
 
289
-			Debugf("Env -----> %v ------ %v\n", config.Env, env)
289
+			utils.Debugf("Env -----> %v ------ %v\n", config.Env, env)
290 290
 
291 291
 			// Create the container and start it
292 292
 			c, err := builder.Create(config)
... ...
@@ -410,7 +411,7 @@ func (builder *Builder) Build(dockerfile io.Reader, stdout io.Writer) (*Image, e
410 410
 			destPath := strings.Trim(tmp[1], " ")
411 411
 			fmt.Fprintf(stdout, "COPY %s to %s in %s\n", sourceUrl, destPath, base.ShortId())
412 412
 
413
-			file, err := Download(sourceUrl, stdout)
413
+			file, err := utils.Download(sourceUrl, stdout)
414 414
 			if err != nil {
415 415
 				return nil, err
416 416
 			}
... ...
@@ -7,6 +7,7 @@ import (
7 7
 	"fmt"
8 8
 	"github.com/dotcloud/docker/auth"
9 9
 	"github.com/dotcloud/docker/term"
10
+	"github.com/dotcloud/docker/utils"
10 11
 	"io"
11 12
 	"io/ioutil"
12 13
 	"net"
... ...
@@ -188,11 +189,11 @@ func CmdLogin(args ...string) error {
188 188
 		return readStringOnRawTerminal(stdin, stdout, false)
189 189
 	}
190 190
 
191
-	oldState, err := SetRawTerminal()
191
+	oldState, err := term.SetRawTerminal()
192 192
 	if err != nil {
193 193
 		return err
194 194
 	} else {
195
-		defer RestoreTerminal(oldState)
195
+		defer term.RestoreTerminal(oldState)
196 196
 	}
197 197
 
198 198
 	cmd := Subcmd("login", "", "Register or Login to the docker registry server")
... ...
@@ -252,7 +253,7 @@ func CmdLogin(args ...string) error {
252 252
 		return err
253 253
 	}
254 254
 	if out2.Status != "" {
255
-		RestoreTerminal(oldState)
255
+		term.RestoreTerminal(oldState)
256 256
 		fmt.Print(out2.Status)
257 257
 	}
258 258
 	return nil
... ...
@@ -303,7 +304,7 @@ func CmdVersion(args ...string) error {
303 303
 	var out ApiVersion
304 304
 	err = json.Unmarshal(body, &out)
305 305
 	if err != nil {
306
-		Debugf("Error unmarshal: body: %s, err: %s\n", body, err)
306
+		utils.Debugf("Error unmarshal: body: %s, err: %s\n", body, err)
307 307
 		return err
308 308
 	}
309 309
 	fmt.Println("Version:", out.Version)
... ...
@@ -519,7 +520,7 @@ func CmdHistory(args ...string) error {
519 519
 	fmt.Fprintln(w, "ID\tCREATED\tCREATED BY")
520 520
 
521 521
 	for _, out := range outs {
522
-		fmt.Fprintf(w, "%s\t%s ago\t%s\n", out.Id, HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.CreatedBy)
522
+		fmt.Fprintf(w, "%s\t%s ago\t%s\n", out.Id, utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.CreatedBy)
523 523
 	}
524 524
 	w.Flush()
525 525
 	return nil
... ...
@@ -742,14 +743,14 @@ func CmdImages(args ...string) error {
742 742
 				if *noTrunc {
743 743
 					fmt.Fprintf(w, "%s\t", out.Id)
744 744
 				} else {
745
-					fmt.Fprintf(w, "%s\t", TruncateId(out.Id))
745
+					fmt.Fprintf(w, "%s\t", utils.TruncateId(out.Id))
746 746
 				}
747
-				fmt.Fprintf(w, "%s ago\n", HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))))
747
+				fmt.Fprintf(w, "%s ago\n", utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))))
748 748
 			} else {
749 749
 				if *noTrunc {
750 750
 					fmt.Fprintln(w, out.Id)
751 751
 				} else {
752
-					fmt.Fprintln(w, TruncateId(out.Id))
752
+					fmt.Fprintln(w, utils.TruncateId(out.Id))
753 753
 				}
754 754
 			}
755 755
 		}
... ...
@@ -809,15 +810,15 @@ func CmdPs(args ...string) error {
809 809
 	for _, out := range outs {
810 810
 		if !*quiet {
811 811
 			if *noTrunc {
812
-				fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s ago\t%s\n", out.Id, out.Image, out.Command, out.Status, HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Ports)
812
+				fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s ago\t%s\n", out.Id, out.Image, out.Command, out.Status, utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Ports)
813 813
 			} else {
814
-				fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s ago\t%s\n", TruncateId(out.Id), out.Image, Trunc(out.Command, 20), out.Status, HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Ports)
814
+				fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s ago\t%s\n", utils.TruncateId(out.Id), out.Image, utils.Trunc(out.Command, 20), out.Status, utils.HumanDuration(time.Now().Sub(time.Unix(out.Created, 0))), out.Ports)
815 815
 			}
816 816
 		} else {
817 817
 			if *noTrunc {
818 818
 				fmt.Fprintln(w, out.Id)
819 819
 			} else {
820
-				fmt.Fprintln(w, TruncateId(out.Id))
820
+				fmt.Fprintln(w, utils.TruncateId(out.Id))
821 821
 			}
822 822
 		}
823 823
 	}
... ...
@@ -1244,20 +1245,20 @@ func hijack(method, path string, setRawTerminal bool) error {
1244 1244
 	rwc, br := clientconn.Hijack()
1245 1245
 	defer rwc.Close()
1246 1246
 
1247
-	receiveStdout := Go(func() error {
1247
+	receiveStdout := utils.Go(func() error {
1248 1248
 		_, err := io.Copy(os.Stdout, br)
1249 1249
 		return err
1250 1250
 	})
1251 1251
 
1252 1252
 	if setRawTerminal && term.IsTerminal(int(os.Stdin.Fd())) && os.Getenv("NORAW") == "" {
1253
-		if oldState, err := SetRawTerminal(); err != nil {
1253
+		if oldState, err := term.SetRawTerminal(); err != nil {
1254 1254
 			return err
1255 1255
 		} else {
1256
-			defer RestoreTerminal(oldState)
1256
+			defer term.RestoreTerminal(oldState)
1257 1257
 		}
1258 1258
 	}
1259 1259
 
1260
-	sendStdin := Go(func() error {
1260
+	sendStdin := utils.Go(func() error {
1261 1261
 		_, err := io.Copy(rwc, os.Stdin)
1262 1262
 		if err := rwc.(*net.TCPConn).CloseWrite(); err != nil {
1263 1263
 			fmt.Fprintf(os.Stderr, "Couldn't send EOF: %s\n", err)
... ...
@@ -4,6 +4,7 @@ import (
4 4
 	"encoding/json"
5 5
 	"flag"
6 6
 	"fmt"
7
+	"github.com/dotcloud/docker/utils"
7 8
 	"github.com/kr/pty"
8 9
 	"io"
9 10
 	"io/ioutil"
... ...
@@ -39,8 +40,8 @@ type Container struct {
39 39
 	ResolvConfPath string
40 40
 
41 41
 	cmd       *exec.Cmd
42
-	stdout    *writeBroadcaster
43
-	stderr    *writeBroadcaster
42
+	stdout    *utils.WriteBroadcaster
43
+	stderr    *utils.WriteBroadcaster
44 44
 	stdin     io.ReadCloser
45 45
 	stdinPipe io.WriteCloser
46 46
 	ptyMaster io.Closer
... ...
@@ -251,9 +252,9 @@ func (container *Container) startPty() error {
251 251
 	// Copy the PTYs to our broadcasters
252 252
 	go func() {
253 253
 		defer container.stdout.CloseWriters()
254
-		Debugf("[startPty] Begin of stdout pipe")
254
+		utils.Debugf("[startPty] Begin of stdout pipe")
255 255
 		io.Copy(container.stdout, ptyMaster)
256
-		Debugf("[startPty] End of stdout pipe")
256
+		utils.Debugf("[startPty] End of stdout pipe")
257 257
 	}()
258 258
 
259 259
 	// stdin
... ...
@@ -262,9 +263,9 @@ func (container *Container) startPty() error {
262 262
 		container.cmd.SysProcAttr = &syscall.SysProcAttr{Setctty: true, Setsid: true}
263 263
 		go func() {
264 264
 			defer container.stdin.Close()
265
-			Debugf("[startPty] Begin of stdin pipe")
265
+			utils.Debugf("[startPty] Begin of stdin pipe")
266 266
 			io.Copy(ptyMaster, container.stdin)
267
-			Debugf("[startPty] End of stdin pipe")
267
+			utils.Debugf("[startPty] End of stdin pipe")
268 268
 		}()
269 269
 	}
270 270
 	if err := container.cmd.Start(); err != nil {
... ...
@@ -284,9 +285,9 @@ func (container *Container) start() error {
284 284
 		}
285 285
 		go func() {
286 286
 			defer stdin.Close()
287
-			Debugf("Begin of stdin pipe [start]")
287
+			utils.Debugf("Begin of stdin pipe [start]")
288 288
 			io.Copy(stdin, container.stdin)
289
-			Debugf("End of stdin pipe [start]")
289
+			utils.Debugf("End of stdin pipe [start]")
290 290
 		}()
291 291
 	}
292 292
 	return container.cmd.Start()
... ...
@@ -303,8 +304,8 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
303 303
 			errors <- err
304 304
 		} else {
305 305
 			go func() {
306
-				Debugf("[start] attach stdin\n")
307
-				defer Debugf("[end] attach stdin\n")
306
+				utils.Debugf("[start] attach stdin\n")
307
+				defer utils.Debugf("[end] attach stdin\n")
308 308
 				// No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr
309 309
 				if cStdout != nil {
310 310
 					defer cStdout.Close()
... ...
@@ -316,12 +317,12 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
316 316
 					defer cStdin.Close()
317 317
 				}
318 318
 				if container.Config.Tty {
319
-					_, err = CopyEscapable(cStdin, stdin)
319
+					_, err = utils.CopyEscapable(cStdin, stdin)
320 320
 				} else {
321 321
 					_, err = io.Copy(cStdin, stdin)
322 322
 				}
323 323
 				if err != nil {
324
-					Debugf("[error] attach stdin: %s\n", err)
324
+					utils.Debugf("[error] attach stdin: %s\n", err)
325 325
 				}
326 326
 				// Discard error, expecting pipe error
327 327
 				errors <- nil
... ...
@@ -335,8 +336,8 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
335 335
 		} else {
336 336
 			cStdout = p
337 337
 			go func() {
338
-				Debugf("[start] attach stdout\n")
339
-				defer Debugf("[end]  attach stdout\n")
338
+				utils.Debugf("[start] attach stdout\n")
339
+				defer utils.Debugf("[end]  attach stdout\n")
340 340
 				// If we are in StdinOnce mode, then close stdin
341 341
 				if container.Config.StdinOnce {
342 342
 					if stdin != nil {
... ...
@@ -348,7 +349,7 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
348 348
 				}
349 349
 				_, err := io.Copy(stdout, cStdout)
350 350
 				if err != nil {
351
-					Debugf("[error] attach stdout: %s\n", err)
351
+					utils.Debugf("[error] attach stdout: %s\n", err)
352 352
 				}
353 353
 				errors <- err
354 354
 			}()
... ...
@@ -361,8 +362,8 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
361 361
 		} else {
362 362
 			cStderr = p
363 363
 			go func() {
364
-				Debugf("[start] attach stderr\n")
365
-				defer Debugf("[end]  attach stderr\n")
364
+				utils.Debugf("[start] attach stderr\n")
365
+				defer utils.Debugf("[end]  attach stderr\n")
366 366
 				// If we are in StdinOnce mode, then close stdin
367 367
 				if container.Config.StdinOnce {
368 368
 					if stdin != nil {
... ...
@@ -374,13 +375,13 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
374 374
 				}
375 375
 				_, err := io.Copy(stderr, cStderr)
376 376
 				if err != nil {
377
-					Debugf("[error] attach stderr: %s\n", err)
377
+					utils.Debugf("[error] attach stderr: %s\n", err)
378 378
 				}
379 379
 				errors <- err
380 380
 			}()
381 381
 		}
382 382
 	}
383
-	return Go(func() error {
383
+	return utils.Go(func() error {
384 384
 		if cStdout != nil {
385 385
 			defer cStdout.Close()
386 386
 		}
... ...
@@ -390,14 +391,14 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
390 390
 		// FIXME: how do clean up the stdin goroutine without the unwanted side effect
391 391
 		// of closing the passed stdin? Add an intermediary io.Pipe?
392 392
 		for i := 0; i < nJobs; i += 1 {
393
-			Debugf("Waiting for job %d/%d\n", i+1, nJobs)
393
+			utils.Debugf("Waiting for job %d/%d\n", i+1, nJobs)
394 394
 			if err := <-errors; err != nil {
395
-				Debugf("Job %d returned error %s. Aborting all jobs\n", i+1, err)
395
+				utils.Debugf("Job %d returned error %s. Aborting all jobs\n", i+1, err)
396 396
 				return err
397 397
 			}
398
-			Debugf("Job %d completed successfully\n", i+1)
398
+			utils.Debugf("Job %d completed successfully\n", i+1)
399 399
 		}
400
-		Debugf("All jobs completed successfully\n")
400
+		utils.Debugf("All jobs completed successfully\n")
401 401
 		return nil
402 402
 	})
403 403
 }
... ...
@@ -555,13 +556,13 @@ func (container *Container) StdinPipe() (io.WriteCloser, error) {
555 555
 func (container *Container) StdoutPipe() (io.ReadCloser, error) {
556 556
 	reader, writer := io.Pipe()
557 557
 	container.stdout.AddWriter(writer)
558
-	return newBufReader(reader), nil
558
+	return utils.NewBufReader(reader), nil
559 559
 }
560 560
 
561 561
 func (container *Container) StderrPipe() (io.ReadCloser, error) {
562 562
 	reader, writer := io.Pipe()
563 563
 	container.stderr.AddWriter(writer)
564
-	return newBufReader(reader), nil
564
+	return utils.NewBufReader(reader), nil
565 565
 }
566 566
 
567 567
 func (container *Container) allocateNetwork() error {
... ...
@@ -609,20 +610,20 @@ func (container *Container) waitLxc() error {
609 609
 
610 610
 func (container *Container) monitor() {
611 611
 	// Wait for the program to exit
612
-	Debugf("Waiting for process")
612
+	utils.Debugf("Waiting for process")
613 613
 
614 614
 	// If the command does not exists, try to wait via lxc
615 615
 	if container.cmd == nil {
616 616
 		if err := container.waitLxc(); err != nil {
617
-			Debugf("%s: Process: %s", container.Id, err)
617
+			utils.Debugf("%s: Process: %s", container.Id, err)
618 618
 		}
619 619
 	} else {
620 620
 		if err := container.cmd.Wait(); err != nil {
621 621
 			// Discard the error as any signals or non 0 returns will generate an error
622
-			Debugf("%s: Process: %s", container.Id, err)
622
+			utils.Debugf("%s: Process: %s", container.Id, err)
623 623
 		}
624 624
 	}
625
-	Debugf("Process finished")
625
+	utils.Debugf("Process finished")
626 626
 
627 627
 	var exitCode int = -1
628 628
 	if container.cmd != nil {
... ...
@@ -633,19 +634,19 @@ func (container *Container) monitor() {
633 633
 	container.releaseNetwork()
634 634
 	if container.Config.OpenStdin {
635 635
 		if err := container.stdin.Close(); err != nil {
636
-			Debugf("%s: Error close stdin: %s", container.Id, err)
636
+			utils.Debugf("%s: Error close stdin: %s", container.Id, err)
637 637
 		}
638 638
 	}
639 639
 	if err := container.stdout.CloseWriters(); err != nil {
640
-		Debugf("%s: Error close stdout: %s", container.Id, err)
640
+		utils.Debugf("%s: Error close stdout: %s", container.Id, err)
641 641
 	}
642 642
 	if err := container.stderr.CloseWriters(); err != nil {
643
-		Debugf("%s: Error close stderr: %s", container.Id, err)
643
+		utils.Debugf("%s: Error close stderr: %s", container.Id, err)
644 644
 	}
645 645
 
646 646
 	if container.ptyMaster != nil {
647 647
 		if err := container.ptyMaster.Close(); err != nil {
648
-			Debugf("%s: Error closing Pty master: %s", container.Id, err)
648
+			utils.Debugf("%s: Error closing Pty master: %s", container.Id, err)
649 649
 		}
650 650
 	}
651 651
 
... ...
@@ -762,7 +763,7 @@ func (container *Container) RwChecksum() (string, error) {
762 762
 	if err != nil {
763 763
 		return "", err
764 764
 	}
765
-	return HashData(rwData)
765
+	return utils.HashData(rwData)
766 766
 }
767 767
 
768 768
 func (container *Container) Export() (Archive, error) {
... ...
@@ -833,7 +834,7 @@ func (container *Container) Unmount() error {
833 833
 // In case of a collision a lookup with Runtime.Get() will fail, and the caller
834 834
 // will need to use a langer prefix, or the full-length container Id.
835 835
 func (container *Container) ShortId() string {
836
-	return TruncateId(container.Id)
836
+	return utils.TruncateId(container.Id)
837 837
 }
838 838
 
839 839
 func (container *Container) logPath(name string) string {
... ...
@@ -4,6 +4,7 @@ import (
4 4
 	"flag"
5 5
 	"fmt"
6 6
 	"github.com/dotcloud/docker"
7
+	"github.com/dotcloud/docker/utils"
7 8
 	"io/ioutil"
8 9
 	"log"
9 10
 	"os"
... ...
@@ -17,7 +18,7 @@ var (
17 17
 )
18 18
 
19 19
 func main() {
20
-	if docker.SelfPath() == "/sbin/init" {
20
+	if utils.SelfPath() == "/sbin/init" {
21 21
 		// Running in init mode
22 22
 		docker.SysInit()
23 23
 		return
... ...
@@ -2,8 +2,9 @@ package docker
2 2
 
3 3
 import (
4 4
 	"fmt"
5
+	"github.com/dotcloud/docker/utils"
5 6
 )
6 7
 
7
-func getKernelVersion() (*KernelVersionInfo, error) {
8
+func getKernelVersion() (*utils.KernelVersionInfo, error) {
8 9
 	return nil, fmt.Errorf("Kernel version detection is not available on darwin")
9 10
 }
... ...
@@ -2,12 +2,14 @@ package docker
2 2
 
3 3
 import (
4 4
 	"bytes"
5
+	"github.com/dotcloud/docker/utils"
5 6
 	"strconv"
6 7
 	"strings"
7 8
 	"syscall"
8 9
 )
9 10
 
10
-func getKernelVersion() (*KernelVersionInfo, error) {
11
+// FIXME: Move this to utils package
12
+func getKernelVersion() (*utils.KernelVersionInfo, error) {
11 13
 	var (
12 14
 		uts                  syscall.Utsname
13 15
 		flavor               string
... ...
@@ -60,7 +62,7 @@ func getKernelVersion() (*KernelVersionInfo, error) {
60 60
 		flavor = ""
61 61
 	}
62 62
 
63
-	return &KernelVersionInfo{
63
+	return &utils.KernelVersionInfo{
64 64
 		Kernel: kernel,
65 65
 		Major:  major,
66 66
 		Minor:  minor,
... ...
@@ -3,6 +3,7 @@ package docker
3 3
 import (
4 4
 	"encoding/json"
5 5
 	"fmt"
6
+	"github.com/dotcloud/docker/utils"
6 7
 	"io"
7 8
 	"io/ioutil"
8 9
 	"net/http"
... ...
@@ -17,7 +18,7 @@ import (
17 17
 // A Graph is a store for versioned filesystem images and the relationship between them.
18 18
 type Graph struct {
19 19
 	Root         string
20
-	idIndex      *TruncIndex
20
+	idIndex      *utils.TruncIndex
21 21
 	httpClient   *http.Client
22 22
 	checksumLock map[string]*sync.Mutex
23 23
 	lockSumFile  *sync.Mutex
... ...
@@ -37,7 +38,7 @@ func NewGraph(root string) (*Graph, error) {
37 37
 	}
38 38
 	graph := &Graph{
39 39
 		Root:         abspath,
40
-		idIndex:      NewTruncIndex(),
40
+		idIndex:      utils.NewTruncIndex(),
41 41
 		checksumLock: make(map[string]*sync.Mutex),
42 42
 		lockSumFile:  &sync.Mutex{},
43 43
 		lockSumMap:   &sync.Mutex{},
... ...
@@ -165,7 +166,7 @@ func (graph *Graph) TempLayerArchive(id string, compression Compression, output
165 165
 	if err != nil {
166 166
 		return nil, err
167 167
 	}
168
-	return NewTempArchive(ProgressReader(ioutil.NopCloser(archive), 0, output, "Buffering to disk %v/%v (%v)"), tmp.Root)
168
+	return NewTempArchive(utils.ProgressReader(ioutil.NopCloser(archive), 0, output, "Buffering to disk %v/%v (%v)"), tmp.Root)
169 169
 }
170 170
 
171 171
 // Mktemp creates a temporary sub-directory inside the graph's filesystem.
... ...
@@ -6,6 +6,7 @@ import (
6 6
 	"encoding/hex"
7 7
 	"encoding/json"
8 8
 	"fmt"
9
+	"github.com/dotcloud/docker/utils"
9 10
 	"io"
10 11
 	"io/ioutil"
11 12
 	"log"
... ...
@@ -180,7 +181,7 @@ func (image *Image) Changes(rw string) ([]Change, error) {
180 180
 }
181 181
 
182 182
 func (image *Image) ShortId() string {
183
-	return TruncateId(image.Id)
183
+	return utils.TruncateId(image.Id)
184 184
 }
185 185
 
186 186
 func ValidateId(id string) error {
... ...
@@ -4,6 +4,7 @@ import (
4 4
 	"encoding/binary"
5 5
 	"errors"
6 6
 	"fmt"
7
+	"github.com/dotcloud/docker/utils"
7 8
 	"io"
8 9
 	"log"
9 10
 	"net"
... ...
@@ -97,7 +98,7 @@ func checkRouteOverlaps(dockerNetwork *net.IPNet) error {
97 97
 	if err != nil {
98 98
 		return err
99 99
 	}
100
-	Debugf("Routes:\n\n%s", output)
100
+	utils.Debugf("Routes:\n\n%s", output)
101 101
 	for _, line := range strings.Split(output, "\n") {
102 102
 		if strings.Trim(line, "\r\n\t ") == "" || strings.Contains(line, "default") {
103 103
 			continue
... ...
@@ -126,13 +127,13 @@ func CreateBridgeIface(ifaceName string) error {
126 126
 			ifaceAddr = addr
127 127
 			break
128 128
 		} else {
129
-			Debugf("%s: %s", addr, err)
129
+			utils.Debugf("%s: %s", addr, err)
130 130
 		}
131 131
 	}
132 132
 	if ifaceAddr == "" {
133 133
 		return fmt.Errorf("Could not find a free IP address range for interface '%s'. Please configure its address manually and run 'docker -b %s'", ifaceName, ifaceName)
134 134
 	} else {
135
-		Debugf("Creating bridge %s with network %s", ifaceName, ifaceAddr)
135
+		utils.Debugf("Creating bridge %s with network %s", ifaceName, ifaceAddr)
136 136
 	}
137 137
 
138 138
 	if output, err := ip("link", "add", ifaceName, "type", "bridge"); err != nil {
... ...
@@ -239,22 +240,22 @@ func (mapper *PortMapper) Map(port int, dest net.TCPAddr) error {
239 239
 // proxy listens for socket connections on `listener`, and forwards them unmodified
240 240
 // to `proto:address`
241 241
 func proxy(listener net.Listener, proto, address string) error {
242
-	Debugf("proxying to %s:%s", proto, address)
243
-	defer Debugf("Done proxying to %s:%s", proto, address)
242
+	utils.Debugf("proxying to %s:%s", proto, address)
243
+	defer utils.Debugf("Done proxying to %s:%s", proto, address)
244 244
 	for {
245
-		Debugf("Listening on %s", listener)
245
+		utils.Debugf("Listening on %s", listener)
246 246
 		src, err := listener.Accept()
247 247
 		if err != nil {
248 248
 			return err
249 249
 		}
250
-		Debugf("Connecting to %s:%s", proto, address)
250
+		utils.Debugf("Connecting to %s:%s", proto, address)
251 251
 		dst, err := net.Dial(proto, address)
252 252
 		if err != nil {
253 253
 			log.Printf("Error connecting to %s:%s: %s", proto, address, err)
254 254
 			src.Close()
255 255
 			continue
256 256
 		}
257
-		Debugf("Connected to backend, splicing")
257
+		utils.Debugf("Connected to backend, splicing")
258 258
 		splice(src, dst)
259 259
 	}
260 260
 	return nil
... ...
@@ -317,7 +318,7 @@ func (alloc *PortAllocator) runFountain() {
317 317
 
318 318
 // FIXME: Release can no longer fail, change its prototype to reflect that.
319 319
 func (alloc *PortAllocator) Release(port int) error {
320
-	Debugf("Releasing %d", port)
320
+	utils.Debugf("Releasing %d", port)
321 321
 	alloc.lock.Lock()
322 322
 	delete(alloc.inUse, port)
323 323
 	alloc.lock.Unlock()
... ...
@@ -325,7 +326,7 @@ func (alloc *PortAllocator) Release(port int) error {
325 325
 }
326 326
 
327 327
 func (alloc *PortAllocator) Acquire(port int) (int, error) {
328
-	Debugf("Acquiring %d", port)
328
+	utils.Debugf("Acquiring %d", port)
329 329
 	if port == 0 {
330 330
 		// Allocate a port from the fountain
331 331
 		for port := range alloc.fountain {
... ...
@@ -5,6 +5,7 @@ import (
5 5
 	"encoding/json"
6 6
 	"fmt"
7 7
 	"github.com/dotcloud/docker/auth"
8
+	"github.com/dotcloud/docker/utils"
8 9
 	"github.com/shin-/cookiejar"
9 10
 	"io"
10 11
 	"io/ioutil"
... ...
@@ -19,7 +20,7 @@ import (
19 19
 func NewImgJson(src []byte) (*Image, error) {
20 20
 	ret := &Image{}
21 21
 
22
-	Debugf("Json string: {%s}\n", src)
22
+	utils.Debugf("Json string: {%s}\n", src)
23 23
 	// FIXME: Is there a cleaner way to "purify" the input json?
24 24
 	if err := json.Unmarshal(src, ret); err != nil {
25 25
 		return nil, err
... ...
@@ -58,7 +59,7 @@ func (graph *Graph) getRemoteHistory(imgId, registry string, token []string) ([]
58 58
 		return nil, fmt.Errorf("Error while reading the http response: %s\n", err)
59 59
 	}
60 60
 
61
-	Debugf("Ancestry: %s", jsonString)
61
+	utils.Debugf("Ancestry: %s", jsonString)
62 62
 	history := new([]string)
63 63
 	if err := json.Unmarshal(jsonString, history); err != nil {
64 64
 		return nil, err
... ...
@@ -116,7 +117,7 @@ func (graph *Graph) getImagesInRepository(repository string, authConfig *auth.Au
116 116
 
117 117
 	err = json.Unmarshal(jsonData, &imageList)
118 118
 	if err != nil {
119
-		Debugf("Body: %s (%s)\n", res.Body, u)
119
+		utils.Debugf("Body: %s (%s)\n", res.Body, u)
120 120
 		return nil, err
121 121
 	}
122 122
 
... ...
@@ -166,7 +167,7 @@ func (graph *Graph) getRemoteImage(stdout io.Writer, imgId, registry string, tok
166 166
 	if err != nil {
167 167
 		return nil, nil, err
168 168
 	}
169
-	return img, ProgressReader(res.Body, int(res.ContentLength), stdout, "Downloading %v/%v (%v)"), nil
169
+	return img, utils.ProgressReader(res.Body, int(res.ContentLength), stdout, "Downloading %v/%v (%v)"), nil
170 170
 }
171 171
 
172 172
 func (graph *Graph) getRemoteTags(stdout io.Writer, registries []string, repository string, token []string) (map[string]string, error) {
... ...
@@ -185,7 +186,7 @@ func (graph *Graph) getRemoteTags(stdout io.Writer, registries []string, reposit
185 185
 		req.Header.Set("Authorization", "Token "+strings.Join(token, ", "))
186 186
 		res, err := client.Do(req)
187 187
 		defer res.Body.Close()
188
-		Debugf("Got status code %d from %s", res.StatusCode, endpoint)
188
+		utils.Debugf("Got status code %d from %s", res.StatusCode, endpoint)
189 189
 		if err != nil || (res.StatusCode != 200 && res.StatusCode != 404) {
190 190
 			continue
191 191
 		} else if res.StatusCode == 404 {
... ...
@@ -416,7 +417,7 @@ func (graph *Graph) PushImage(stdout io.Writer, img *Image, registry string, tok
416 416
 		return fmt.Errorf("Error while retrieving checksum for %s: %v", img.Id, err)
417 417
 	}
418 418
 	req.Header.Set("X-Docker-Checksum", checksum)
419
-	Debugf("Setting checksum for %s: %s", img.ShortId(), checksum)
419
+	utils.Debugf("Setting checksum for %s: %s", img.ShortId(), checksum)
420 420
 	res, err := doWithCookies(client, req)
421 421
 	if err != nil {
422 422
 		return fmt.Errorf("Failed to upload metadata: %s", err)
... ...
@@ -469,8 +470,7 @@ func (graph *Graph) PushImage(stdout io.Writer, img *Image, registry string, tok
469 469
 		layerData = &TempArchive{file, st.Size()}
470 470
 	}
471 471
 
472
-	req3, err := http.NewRequest("PUT", registry+"/images/"+img.Id+"/layer",
473
-		ProgressReader(layerData, int(layerData.Size), stdout, ""))
472
+	req3, err := http.NewRequest("PUT", registry+"/images/"+img.Id+"/layer", utils.ProgressReader(layerData, int(layerData.Size), stdout, ""))
474 473
 	if err != nil {
475 474
 		return err
476 475
 	}
... ...
@@ -502,7 +502,7 @@ func (graph *Graph) pushTag(remote, revision, tag, registry string, token []stri
502 502
 	revision = "\"" + revision + "\""
503 503
 	registry = "https://" + registry + "/v1"
504 504
 
505
-	Debugf("Pushing tags for rev [%s] on {%s}\n", revision, registry+"/users/"+remote+"/"+tag)
505
+	utils.Debugf("Pushing tags for rev [%s] on {%s}\n", revision, registry+"/users/"+remote+"/"+tag)
506 506
 
507 507
 	client := graph.getHttpClient()
508 508
 	req, err := http.NewRequest("PUT", registry+"/repositories/"+remote+"/tags/"+tag, strings.NewReader(revision))
... ...
@@ -624,7 +624,7 @@ func (graph *Graph) PushRepository(stdout io.Writer, remote string, localRepo Re
624 624
 		return err
625 625
 	}
626 626
 
627
-	Debugf("json sent: %s\n", imgListJson)
627
+	utils.Debugf("json sent: %s\n", imgListJson)
628 628
 
629 629
 	fmt.Fprintf(stdout, "Sending image list\n")
630 630
 	req, err := http.NewRequest("PUT", auth.IndexServerAddress()+"/repositories/"+remote+"/", bytes.NewReader(imgListJson))
... ...
@@ -642,7 +642,7 @@ func (graph *Graph) PushRepository(stdout io.Writer, remote string, localRepo Re
642 642
 	defer res.Body.Close()
643 643
 
644 644
 	for res.StatusCode >= 300 && res.StatusCode < 400 {
645
-		Debugf("Redirected to %s\n", res.Header.Get("Location"))
645
+		utils.Debugf("Redirected to %s\n", res.Header.Get("Location"))
646 646
 		req, err = http.NewRequest("PUT", res.Header.Get("Location"), bytes.NewReader(imgListJson))
647 647
 		if err != nil {
648 648
 			return err
... ...
@@ -669,7 +669,7 @@ func (graph *Graph) PushRepository(stdout io.Writer, remote string, localRepo Re
669 669
 	var token, endpoints []string
670 670
 	if res.Header.Get("X-Docker-Token") != "" {
671 671
 		token = res.Header["X-Docker-Token"]
672
-		Debugf("Auth token: %v", token)
672
+		utils.Debugf("Auth token: %v", token)
673 673
 	} else {
674 674
 		return fmt.Errorf("Index response didn't contain an access token")
675 675
 	}
... ...
@@ -4,6 +4,7 @@ import (
4 4
 	"container/list"
5 5
 	"fmt"
6 6
 	"github.com/dotcloud/docker/auth"
7
+	"github.com/dotcloud/docker/utils"
7 8
 	"io"
8 9
 	"io/ioutil"
9 10
 	"log"
... ...
@@ -27,9 +28,9 @@ type Runtime struct {
27 27
 	graph          *Graph
28 28
 	repositories   *TagStore
29 29
 	authConfig     *auth.AuthConfig
30
-	idIndex        *TruncIndex
30
+	idIndex        *utils.TruncIndex
31 31
 	capabilities   *Capabilities
32
-	kernelVersion  *KernelVersionInfo
32
+	kernelVersion  *utils.KernelVersionInfo
33 33
 	autoRestart    bool
34 34
 	volumes        *Graph
35 35
 }
... ...
@@ -37,7 +38,7 @@ type Runtime struct {
37 37
 var sysInitPath string
38 38
 
39 39
 func init() {
40
-	sysInitPath = SelfPath()
40
+	sysInitPath = utils.SelfPath()
41 41
 }
42 42
 
43 43
 func (runtime *Runtime) List() []*Container {
... ...
@@ -113,13 +114,13 @@ func (runtime *Runtime) Register(container *Container) error {
113 113
 	container.runtime = runtime
114 114
 
115 115
 	// Attach to stdout and stderr
116
-	container.stderr = newWriteBroadcaster()
117
-	container.stdout = newWriteBroadcaster()
116
+	container.stderr = utils.NewWriteBroadcaster()
117
+	container.stdout = utils.NewWriteBroadcaster()
118 118
 	// Attach to stdin
119 119
 	if container.Config.OpenStdin {
120 120
 		container.stdin, container.stdinPipe = io.Pipe()
121 121
 	} else {
122
-		container.stdinPipe = NopWriteCloser(ioutil.Discard) // Silently drop stdin
122
+		container.stdinPipe = utils.NopWriteCloser(ioutil.Discard) // Silently drop stdin
123 123
 	}
124 124
 	// done
125 125
 	runtime.containers.PushBack(container)
... ...
@@ -137,9 +138,9 @@ func (runtime *Runtime) Register(container *Container) error {
137 137
 			return err
138 138
 		} else {
139 139
 			if !strings.Contains(string(output), "RUNNING") {
140
-				Debugf("Container %s was supposed to be running be is not.", container.Id)
140
+				utils.Debugf("Container %s was supposed to be running be is not.", container.Id)
141 141
 				if runtime.autoRestart {
142
-					Debugf("Restarting")
142
+					utils.Debugf("Restarting")
143 143
 					container.State.Ghost = false
144 144
 					container.State.setStopped(0)
145 145
 					if err := container.Start(); err != nil {
... ...
@@ -147,7 +148,7 @@ func (runtime *Runtime) Register(container *Container) error {
147 147
 					}
148 148
 					nomonitor = true
149 149
 				} else {
150
-					Debugf("Marking as stopped")
150
+					utils.Debugf("Marking as stopped")
151 151
 					container.State.setStopped(-127)
152 152
 					if err := container.ToDisk(); err != nil {
153 153
 						return err
... ...
@@ -168,7 +169,7 @@ func (runtime *Runtime) Register(container *Container) error {
168 168
 	return nil
169 169
 }
170 170
 
171
-func (runtime *Runtime) LogToDisk(src *writeBroadcaster, dst string) error {
171
+func (runtime *Runtime) LogToDisk(src *utils.WriteBroadcaster, dst string) error {
172 172
 	log, err := os.OpenFile(dst, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0600)
173 173
 	if err != nil {
174 174
 		return err
... ...
@@ -215,16 +216,16 @@ func (runtime *Runtime) restore() error {
215 215
 		id := v.Name()
216 216
 		container, err := runtime.Load(id)
217 217
 		if err != nil {
218
-			Debugf("Failed to load container %v: %v", id, err)
218
+			utils.Debugf("Failed to load container %v: %v", id, err)
219 219
 			continue
220 220
 		}
221
-		Debugf("Loaded container %v", container.Id)
221
+		utils.Debugf("Loaded container %v", container.Id)
222 222
 	}
223 223
 	return nil
224 224
 }
225 225
 
226 226
 func (runtime *Runtime) UpdateCapabilities(quiet bool) {
227
-	if cgroupMemoryMountpoint, err := FindCgroupMountpoint("memory"); err != nil {
227
+	if cgroupMemoryMountpoint, err := utils.FindCgroupMountpoint("memory"); err != nil {
228 228
 		if !quiet {
229 229
 			log.Printf("WARNING: %s\n", err)
230 230
 		}
... ...
@@ -255,7 +256,7 @@ func NewRuntime(autoRestart bool) (*Runtime, error) {
255 255
 		log.Printf("WARNING: %s\n", err)
256 256
 	} else {
257 257
 		runtime.kernelVersion = k
258
-		if CompareKernelVersion(k, &KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0}) < 0 {
258
+		if utils.CompareKernelVersion(k, &utils.KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0}) < 0 {
259 259
 			log.Printf("WARNING: You are running linux kernel version %s, which might be unstable running docker. Please upgrade your kernel to 3.8.0.", k.String())
260 260
 		}
261 261
 	}
... ...
@@ -302,7 +303,7 @@ func NewRuntimeFromDirectory(root string, autoRestart bool) (*Runtime, error) {
302 302
 		graph:          g,
303 303
 		repositories:   repositories,
304 304
 		authConfig:     authConfig,
305
-		idIndex:        NewTruncIndex(),
305
+		idIndex:        utils.NewTruncIndex(),
306 306
 		capabilities:   &Capabilities{},
307 307
 		autoRestart:    autoRestart,
308 308
 		volumes:        volumes,
... ...
@@ -2,6 +2,7 @@ package docker
2 2
 
3 3
 import (
4 4
 	"fmt"
5
+	"github.com/dotcloud/docker/utils"
5 6
 	"io"
6 7
 	"log"
7 8
 	"net/http"
... ...
@@ -54,7 +55,7 @@ func (srv *Server) ImagesSearch(term string) ([]ApiSearch, error) {
54 54
 		var out ApiSearch
55 55
 		out.Description = repo["description"]
56 56
 		if len(out.Description) > 45 {
57
-			out.Description = Trunc(out.Description, 42) + "..."
57
+			out.Description = utils.Trunc(out.Description, 42) + "..."
58 58
 		}
59 59
 		out.Name = repo["name"]
60 60
 		outs = append(outs, out)
... ...
@@ -68,7 +69,7 @@ func (srv *Server) ImageInsert(name, url, path string, out io.Writer) error {
68 68
 		return err
69 69
 	}
70 70
 
71
-	file, err := Download(url, out)
71
+	file, err := utils.Download(url, out)
72 72
 	if err != nil {
73 73
 		return err
74 74
 	}
... ...
@@ -85,7 +86,7 @@ func (srv *Server) ImageInsert(name, url, path string, out io.Writer) error {
85 85
 		return err
86 86
 	}
87 87
 
88
-	if err := c.Inject(ProgressReader(file.Body, int(file.ContentLength), out, "Downloading %v/%v (%v)"), path); err != nil {
88
+	if err := c.Inject(utils.ProgressReader(file.Body, int(file.ContentLength), out, "Downloading %v/%v (%v)"), path); err != nil {
89 89
 		return err
90 90
 	}
91 91
 	// FIXME: Handle custom repo, tag comment, author
... ...
@@ -124,7 +125,7 @@ func (srv *Server) ImagesViz(out io.Writer) error {
124 124
 
125 125
 	for name, repository := range srv.runtime.repositories.Repositories {
126 126
 		for tag, id := range repository {
127
-			reporefs[TruncateId(id)] = append(reporefs[TruncateId(id)], fmt.Sprintf("%s:%s", name, tag))
127
+			reporefs[utils.TruncateId(id)] = append(reporefs[utils.TruncateId(id)], fmt.Sprintf("%s:%s", name, tag))
128 128
 		}
129 129
 	}
130 130
 
... ...
@@ -193,7 +194,7 @@ func (srv *Server) DockerInfo() ApiInfo {
193 193
 	out.GoVersion = runtime.Version()
194 194
 	if os.Getenv("DEBUG") != "" {
195 195
 		out.Debug = true
196
-		out.NFd = getTotalUsedFds()
196
+		out.NFd = utils.GetTotalUsedFds()
197 197
 		out.NGoroutines = runtime.NumGoroutine()
198 198
 	}
199 199
 	return out
... ...
@@ -299,7 +300,7 @@ func (srv *Server) ImagePull(name, tag, registry string, out io.Writer) error {
299 299
 func (srv *Server) ImagePush(name, registry string, out io.Writer) error {
300 300
 	img, err := srv.runtime.graph.Get(name)
301 301
 	if err != nil {
302
-		Debugf("The push refers to a repository [%s] (len: %d)\n", name, len(srv.runtime.repositories.Repositories[name]))
302
+		utils.Debugf("The push refers to a repository [%s] (len: %d)\n", name, len(srv.runtime.repositories.Repositories[name]))
303 303
 		// If it fails, try to get the repository
304 304
 		if localRepo, exists := srv.runtime.repositories.Repositories[name]; exists {
305 305
 			if err := srv.runtime.graph.PushRepository(out, name, localRepo, srv.runtime.authConfig); err != nil {
... ...
@@ -336,11 +337,11 @@ func (srv *Server) ImageImport(src, repo, tag string, in io.Reader, out io.Write
336 336
 		fmt.Fprintln(out, "Downloading from", u)
337 337
 		// Download with curl (pretty progress bar)
338 338
 		// If curl is not available, fallback to http.Get()
339
-		resp, err = Download(u.String(), out)
339
+		resp, err = utils.Download(u.String(), out)
340 340
 		if err != nil {
341 341
 			return err
342 342
 		}
343
-		archive = ProgressReader(resp.Body, int(resp.ContentLength), out, "Importing %v/%v (%v)")
343
+		archive = utils.ProgressReader(resp.Body, int(resp.ContentLength), out, "Importing %v/%v (%v)")
344 344
 	}
345 345
 	img, err := srv.runtime.graph.Create(archive, nil, "Imported from "+src, "", nil)
346 346
 	if err != nil {
... ...
@@ -486,17 +487,17 @@ func (srv *Server) ContainerAttach(name string, logs, stream, stdin, stdout, std
486 486
 		if stdout {
487 487
 			cLog, err := container.ReadLog("stdout")
488 488
 			if err != nil {
489
-				Debugf(err.Error())
489
+				utils.Debugf(err.Error())
490 490
 			} else if _, err := io.Copy(out, cLog); err != nil {
491
-				Debugf(err.Error())
491
+				utils.Debugf(err.Error())
492 492
 			}
493 493
 		}
494 494
 		if stderr {
495 495
 			cLog, err := container.ReadLog("stderr")
496 496
 			if err != nil {
497
-				Debugf(err.Error())
497
+				utils.Debugf(err.Error())
498 498
 			} else if _, err := io.Copy(out, cLog); err != nil {
499
-				Debugf(err.Error())
499
+				utils.Debugf(err.Error())
500 500
 			}
501 501
 		}
502 502
 	}
... ...
@@ -517,7 +518,7 @@ func (srv *Server) ContainerAttach(name string, logs, stream, stdin, stdout, std
517 517
 			r, w := io.Pipe()
518 518
 			go func() {
519 519
 				defer w.Close()
520
-				defer Debugf("Closing buffered stdin pipe")
520
+				defer utils.Debugf("Closing buffered stdin pipe")
521 521
 				io.Copy(w, in)
522 522
 			}()
523 523
 			cStdin = r
... ...
@@ -2,6 +2,7 @@ package docker
2 2
 
3 3
 import (
4 4
 	"fmt"
5
+	"github.com/dotcloud/docker/utils"
5 6
 	"sync"
6 7
 	"time"
7 8
 )
... ...
@@ -21,7 +22,7 @@ func (s *State) String() string {
21 21
 		if s.Ghost {
22 22
 			return fmt.Sprintf("Ghost")
23 23
 		}
24
-		return fmt.Sprintf("Up %s", HumanDuration(time.Now().Sub(s.StartedAt)))
24
+		return fmt.Sprintf("Up %s", utils.HumanDuration(time.Now().Sub(s.StartedAt)))
25 25
 	}
26 26
 	return fmt.Sprintf("Exit %d", s.ExitCode)
27 27
 }
... ...
@@ -3,6 +3,7 @@ package docker
3 3
 import (
4 4
 	"encoding/json"
5 5
 	"fmt"
6
+	"github.com/dotcloud/docker/utils"
6 7
 	"io/ioutil"
7 8
 	"os"
8 9
 	"path/filepath"
... ...
@@ -106,7 +107,7 @@ func (store *TagStore) ImageName(id string) string {
106 106
 	if names, exists := store.ById()[id]; exists && len(names) > 0 {
107 107
 		return names[0]
108 108
 	}
109
-	return TruncateId(id)
109
+	return utils.TruncateId(id)
110 110
 }
111 111
 
112 112
 func (store *TagStore) Set(repoName, tag, imageName string, force bool) error {
... ...
@@ -1,6 +1,8 @@
1 1
 package term
2 2
 
3 3
 import (
4
+	"os"
5
+	"os/signal"
4 6
 	"syscall"
5 7
 	"unsafe"
6 8
 )
... ...
@@ -120,3 +122,22 @@ func Restore(fd int, state *State) error {
120 120
 	_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(setTermios), uintptr(unsafe.Pointer(&state.termios)), 0, 0, 0)
121 121
 	return err
122 122
 }
123
+
124
+func SetRawTerminal() (*State, error) {
125
+	oldState, err := MakeRaw(int(os.Stdin.Fd()))
126
+	if err != nil {
127
+		return nil, err
128
+	}
129
+	c := make(chan os.Signal, 1)
130
+	signal.Notify(c, os.Interrupt)
131
+	go func() {
132
+		_ = <-c
133
+		Restore(int(os.Stdin.Fd()), oldState)
134
+		os.Exit(0)
135
+	}()
136
+	return oldState, err
137
+}
138
+
139
+func RestoreTerminal(state *State) {
140
+	Restore(int(os.Stdin.Fd()), state)
141
+}
... ...
@@ -1,500 +1,9 @@
1 1
 package docker
2 2
 
3 3
 import (
4
-	"bytes"
5
-	"crypto/sha256"
6
-	"encoding/hex"
7
-	"errors"
8
-	"fmt"
9
-	"github.com/dotcloud/docker/term"
10
-	"index/suffixarray"
11
-	"io"
12
-	"io/ioutil"
13
-	"net/http"
14
-	"os"
15
-	"os/exec"
16
-	"os/signal"
17
-	"path/filepath"
18
-	"runtime"
19
-	"strings"
20
-	"sync"
21
-	"time"
4
+	"github.com/dotcloud/docker/utils"
22 5
 )
23 6
 
24
-// Go is a basic promise implementation: it wraps calls a function in a goroutine,
25
-// and returns a channel which will later return the function's return value.
26
-func Go(f func() error) chan error {
27
-	ch := make(chan error)
28
-	go func() {
29
-		ch <- f()
30
-	}()
31
-	return ch
32
-}
33
-
34
-// Request a given URL and return an io.Reader
35
-func Download(url string, stderr io.Writer) (*http.Response, error) {
36
-	var resp *http.Response
37
-	var err error = nil
38
-	if resp, err = http.Get(url); err != nil {
39
-		return nil, err
40
-	}
41
-	if resp.StatusCode >= 400 {
42
-		return nil, errors.New("Got HTTP status code >= 400: " + resp.Status)
43
-	}
44
-	return resp, nil
45
-}
46
-
47
-// Debug function, if the debug flag is set, then display. Do nothing otherwise
48
-// If Docker is in damon mode, also send the debug info on the socket
49
-func Debugf(format string, a ...interface{}) {
50
-	if os.Getenv("DEBUG") != "" {
51
-
52
-		// Retrieve the stack infos
53
-		_, file, line, ok := runtime.Caller(1)
54
-		if !ok {
55
-			file = "<unknown>"
56
-			line = -1
57
-		} else {
58
-			file = file[strings.LastIndex(file, "/")+1:]
59
-		}
60
-
61
-		fmt.Fprintf(os.Stderr, fmt.Sprintf("[debug] %s:%d %s\n", file, line, format), a...)
62
-	}
63
-}
64
-
65
-// Reader with progress bar
66
-type progressReader struct {
67
-	reader       io.ReadCloser // Stream to read from
68
-	output       io.Writer     // Where to send progress bar to
69
-	readTotal    int           // Expected stream length (bytes)
70
-	readProgress int           // How much has been read so far (bytes)
71
-	lastUpdate   int           // How many bytes read at least update
72
-	template     string        // Template to print. Default "%v/%v (%v)"
73
-}
74
-
75
-func (r *progressReader) Read(p []byte) (n int, err error) {
76
-	read, err := io.ReadCloser(r.reader).Read(p)
77
-	r.readProgress += read
78
-
79
-	updateEvery := 4096
80
-	if r.readTotal > 0 {
81
-		// Only update progress for every 1% read
82
-		if increment := int(0.01 * float64(r.readTotal)); increment > updateEvery {
83
-			updateEvery = increment
84
-		}
85
-	}
86
-	if r.readProgress-r.lastUpdate > updateEvery || err != nil {
87
-		if r.readTotal > 0 {
88
-			fmt.Fprintf(r.output, r.template+"\r", r.readProgress, r.readTotal, fmt.Sprintf("%.0f%%", float64(r.readProgress)/float64(r.readTotal)*100))
89
-		} else {
90
-			fmt.Fprintf(r.output, r.template+"\r", r.readProgress, "?", "n/a")
91
-		}
92
-		r.lastUpdate = r.readProgress
93
-	}
94
-	// Send newline when complete
95
-	if err != nil {
96
-		fmt.Fprintf(r.output, "\n")
97
-	}
98
-
99
-	return read, err
100
-}
101
-func (r *progressReader) Close() error {
102
-	return io.ReadCloser(r.reader).Close()
103
-}
104
-func ProgressReader(r io.ReadCloser, size int, output io.Writer, template string) *progressReader {
105
-	if template == "" {
106
-		template = "%v/%v (%v)"
107
-	}
108
-	return &progressReader{r, output, size, 0, 0, template}
109
-}
110
-
111
-// HumanDuration returns a human-readable approximation of a duration
112
-// (eg. "About a minute", "4 hours ago", etc.)
113
-func HumanDuration(d time.Duration) string {
114
-	if seconds := int(d.Seconds()); seconds < 1 {
115
-		return "Less than a second"
116
-	} else if seconds < 60 {
117
-		return fmt.Sprintf("%d seconds", seconds)
118
-	} else if minutes := int(d.Minutes()); minutes == 1 {
119
-		return "About a minute"
120
-	} else if minutes < 60 {
121
-		return fmt.Sprintf("%d minutes", minutes)
122
-	} else if hours := int(d.Hours()); hours == 1 {
123
-		return "About an hour"
124
-	} else if hours < 48 {
125
-		return fmt.Sprintf("%d hours", hours)
126
-	} else if hours < 24*7*2 {
127
-		return fmt.Sprintf("%d days", hours/24)
128
-	} else if hours < 24*30*3 {
129
-		return fmt.Sprintf("%d weeks", hours/24/7)
130
-	} else if hours < 24*365*2 {
131
-		return fmt.Sprintf("%d months", hours/24/30)
132
-	}
133
-	return fmt.Sprintf("%d years", d.Hours()/24/365)
134
-}
135
-
136
-func Trunc(s string, maxlen int) string {
137
-	if len(s) <= maxlen {
138
-		return s
139
-	}
140
-	return s[:maxlen]
141
-}
142
-
143
-// Figure out the absolute path of our own binary
144
-func SelfPath() string {
145
-	path, err := exec.LookPath(os.Args[0])
146
-	if err != nil {
147
-		panic(err)
148
-	}
149
-	path, err = filepath.Abs(path)
150
-	if err != nil {
151
-		panic(err)
152
-	}
153
-	return path
154
-}
155
-
156
-type nopWriter struct {
157
-}
158
-
159
-func (w *nopWriter) Write(buf []byte) (int, error) {
160
-	return len(buf), nil
161
-}
162
-
163
-type nopWriteCloser struct {
164
-	io.Writer
165
-}
166
-
167
-func (w *nopWriteCloser) Close() error { return nil }
168
-
169
-func NopWriteCloser(w io.Writer) io.WriteCloser {
170
-	return &nopWriteCloser{w}
171
-}
172
-
173
-type bufReader struct {
174
-	buf    *bytes.Buffer
175
-	reader io.Reader
176
-	err    error
177
-	l      sync.Mutex
178
-	wait   sync.Cond
179
-}
180
-
181
-func newBufReader(r io.Reader) *bufReader {
182
-	reader := &bufReader{
183
-		buf:    &bytes.Buffer{},
184
-		reader: r,
185
-	}
186
-	reader.wait.L = &reader.l
187
-	go reader.drain()
188
-	return reader
189
-}
190
-
191
-func (r *bufReader) drain() {
192
-	buf := make([]byte, 1024)
193
-	for {
194
-		n, err := r.reader.Read(buf)
195
-		r.l.Lock()
196
-		if err != nil {
197
-			r.err = err
198
-		} else {
199
-			r.buf.Write(buf[0:n])
200
-		}
201
-		r.wait.Signal()
202
-		r.l.Unlock()
203
-		if err != nil {
204
-			break
205
-		}
206
-	}
207
-}
208
-
209
-func (r *bufReader) Read(p []byte) (n int, err error) {
210
-	r.l.Lock()
211
-	defer r.l.Unlock()
212
-	for {
213
-		n, err = r.buf.Read(p)
214
-		if n > 0 {
215
-			return n, err
216
-		}
217
-		if r.err != nil {
218
-			return 0, r.err
219
-		}
220
-		r.wait.Wait()
221
-	}
222
-	panic("unreachable")
223
-}
224
-
225
-func (r *bufReader) Close() error {
226
-	closer, ok := r.reader.(io.ReadCloser)
227
-	if !ok {
228
-		return nil
229
-	}
230
-	return closer.Close()
231
-}
232
-
233
-type writeBroadcaster struct {
234
-	mu      sync.Mutex
235
-	writers map[io.WriteCloser]struct{}
236
-}
237
-
238
-func (w *writeBroadcaster) AddWriter(writer io.WriteCloser) {
239
-	w.mu.Lock()
240
-	w.writers[writer] = struct{}{}
241
-	w.mu.Unlock()
242
-}
243
-
244
-// FIXME: Is that function used?
245
-// FIXME: This relies on the concrete writer type used having equality operator
246
-func (w *writeBroadcaster) RemoveWriter(writer io.WriteCloser) {
247
-	w.mu.Lock()
248
-	delete(w.writers, writer)
249
-	w.mu.Unlock()
250
-}
251
-
252
-func (w *writeBroadcaster) Write(p []byte) (n int, err error) {
253
-	w.mu.Lock()
254
-	defer w.mu.Unlock()
255
-	for writer := range w.writers {
256
-		if n, err := writer.Write(p); err != nil || n != len(p) {
257
-			// On error, evict the writer
258
-			delete(w.writers, writer)
259
-		}
260
-	}
261
-	return len(p), nil
262
-}
263
-
264
-func (w *writeBroadcaster) CloseWriters() error {
265
-	w.mu.Lock()
266
-	defer w.mu.Unlock()
267
-	for writer := range w.writers {
268
-		writer.Close()
269
-	}
270
-	w.writers = make(map[io.WriteCloser]struct{})
271
-	return nil
272
-}
273
-
274
-func newWriteBroadcaster() *writeBroadcaster {
275
-	return &writeBroadcaster{writers: make(map[io.WriteCloser]struct{})}
276
-}
277
-
278
-func getTotalUsedFds() int {
279
-	if fds, err := ioutil.ReadDir(fmt.Sprintf("/proc/%d/fd", os.Getpid())); err != nil {
280
-		Debugf("Error opening /proc/%d/fd: %s", os.Getpid(), err)
281
-	} else {
282
-		return len(fds)
283
-	}
284
-	return -1
285
-}
286
-
287
-// TruncIndex allows the retrieval of string identifiers by any of their unique prefixes.
288
-// This is used to retrieve image and container IDs by more convenient shorthand prefixes.
289
-type TruncIndex struct {
290
-	index *suffixarray.Index
291
-	ids   map[string]bool
292
-	bytes []byte
293
-}
294
-
295
-func NewTruncIndex() *TruncIndex {
296
-	return &TruncIndex{
297
-		index: suffixarray.New([]byte{' '}),
298
-		ids:   make(map[string]bool),
299
-		bytes: []byte{' '},
300
-	}
301
-}
302
-
303
-func (idx *TruncIndex) Add(id string) error {
304
-	if strings.Contains(id, " ") {
305
-		return fmt.Errorf("Illegal character: ' '")
306
-	}
307
-	if _, exists := idx.ids[id]; exists {
308
-		return fmt.Errorf("Id already exists: %s", id)
309
-	}
310
-	idx.ids[id] = true
311
-	idx.bytes = append(idx.bytes, []byte(id+" ")...)
312
-	idx.index = suffixarray.New(idx.bytes)
313
-	return nil
314
-}
315
-
316
-func (idx *TruncIndex) Delete(id string) error {
317
-	if _, exists := idx.ids[id]; !exists {
318
-		return fmt.Errorf("No such id: %s", id)
319
-	}
320
-	before, after, err := idx.lookup(id)
321
-	if err != nil {
322
-		return err
323
-	}
324
-	delete(idx.ids, id)
325
-	idx.bytes = append(idx.bytes[:before], idx.bytes[after:]...)
326
-	idx.index = suffixarray.New(idx.bytes)
327
-	return nil
328
-}
329
-
330
-func (idx *TruncIndex) lookup(s string) (int, int, error) {
331
-	offsets := idx.index.Lookup([]byte(" "+s), -1)
332
-	//log.Printf("lookup(%s): %v (index bytes: '%s')\n", s, offsets, idx.index.Bytes())
333
-	if offsets == nil || len(offsets) == 0 || len(offsets) > 1 {
334
-		return -1, -1, fmt.Errorf("No such id: %s", s)
335
-	}
336
-	offsetBefore := offsets[0] + 1
337
-	offsetAfter := offsetBefore + strings.Index(string(idx.bytes[offsetBefore:]), " ")
338
-	return offsetBefore, offsetAfter, nil
339
-}
340
-
341
-func (idx *TruncIndex) Get(s string) (string, error) {
342
-	before, after, err := idx.lookup(s)
343
-	//log.Printf("Get(%s) bytes=|%s| before=|%d| after=|%d|\n", s, idx.bytes, before, after)
344
-	if err != nil {
345
-		return "", err
346
-	}
347
-	return string(idx.bytes[before:after]), err
348
-}
349
-
350
-// TruncateId returns a shorthand version of a string identifier for convenience.
351
-// A collision with other shorthands is very unlikely, but possible.
352
-// In case of a collision a lookup with TruncIndex.Get() will fail, and the caller
353
-// will need to use a langer prefix, or the full-length Id.
354
-func TruncateId(id string) string {
355
-	shortLen := 12
356
-	if len(id) < shortLen {
357
-		shortLen = len(id)
358
-	}
359
-	return id[:shortLen]
360
-}
361
-
362
-// Code c/c from io.Copy() modified to handle escape sequence
363
-func CopyEscapable(dst io.Writer, src io.ReadCloser) (written int64, err error) {
364
-	buf := make([]byte, 32*1024)
365
-	for {
366
-		nr, er := src.Read(buf)
367
-		if nr > 0 {
368
-			// ---- Docker addition
369
-			// char 16 is C-p
370
-			if nr == 1 && buf[0] == 16 {
371
-				nr, er = src.Read(buf)
372
-				// char 17 is C-q
373
-				if nr == 1 && buf[0] == 17 {
374
-					if err := src.Close(); err != nil {
375
-						return 0, err
376
-					}
377
-					return 0, io.EOF
378
-				}
379
-			}
380
-			// ---- End of docker
381
-			nw, ew := dst.Write(buf[0:nr])
382
-			if nw > 0 {
383
-				written += int64(nw)
384
-			}
385
-			if ew != nil {
386
-				err = ew
387
-				break
388
-			}
389
-			if nr != nw {
390
-				err = io.ErrShortWrite
391
-				break
392
-			}
393
-		}
394
-		if er == io.EOF {
395
-			break
396
-		}
397
-		if er != nil {
398
-			err = er
399
-			break
400
-		}
401
-	}
402
-	return written, err
403
-}
404
-
405
-func SetRawTerminal() (*term.State, error) {
406
-	oldState, err := term.MakeRaw(int(os.Stdin.Fd()))
407
-	if err != nil {
408
-		return nil, err
409
-	}
410
-	c := make(chan os.Signal, 1)
411
-	signal.Notify(c, os.Interrupt)
412
-	go func() {
413
-		_ = <-c
414
-		term.Restore(int(os.Stdin.Fd()), oldState)
415
-		os.Exit(0)
416
-	}()
417
-	return oldState, err
418
-}
419
-
420
-func RestoreTerminal(state *term.State) {
421
-	term.Restore(int(os.Stdin.Fd()), state)
422
-}
423
-
424
-func HashData(src io.Reader) (string, error) {
425
-	h := sha256.New()
426
-	if _, err := io.Copy(h, src); err != nil {
427
-		return "", err
428
-	}
429
-	return "sha256:" + hex.EncodeToString(h.Sum(nil)), nil
430
-}
431
-
432
-type KernelVersionInfo struct {
433
-	Kernel int
434
-	Major  int
435
-	Minor  int
436
-	Flavor string
437
-}
438
-
439
-// FIXME: this doens't build on Darwin
440
-func GetKernelVersion() (*KernelVersionInfo, error) {
441
-	return getKernelVersion()
442
-}
443
-
444
-func (k *KernelVersionInfo) String() string {
445
-	flavor := ""
446
-	if len(k.Flavor) > 0 {
447
-		flavor = fmt.Sprintf("-%s", k.Flavor)
448
-	}
449
-	return fmt.Sprintf("%d.%d.%d%s", k.Kernel, k.Major, k.Minor, flavor)
450
-}
451
-
452
-// Compare two KernelVersionInfo struct.
453
-// Returns -1 if a < b, = if a == b, 1 it a > b
454
-func CompareKernelVersion(a, b *KernelVersionInfo) int {
455
-	if a.Kernel < b.Kernel {
456
-		return -1
457
-	} else if a.Kernel > b.Kernel {
458
-		return 1
459
-	}
460
-
461
-	if a.Major < b.Major {
462
-		return -1
463
-	} else if a.Major > b.Major {
464
-		return 1
465
-	}
466
-
467
-	if a.Minor < b.Minor {
468
-		return -1
469
-	} else if a.Minor > b.Minor {
470
-		return 1
471
-	}
472
-
473
-	return 0
474
-}
475
-
476
-func FindCgroupMountpoint(cgroupType string) (string, error) {
477
-	output, err := ioutil.ReadFile("/proc/mounts")
478
-	if err != nil {
479
-		return "", err
480
-	}
481
-
482
-	// /proc/mounts has 6 fields per line, one mount per line, e.g.
483
-	// cgroup /sys/fs/cgroup/devices cgroup rw,relatime,devices 0 0
484
-	for _, line := range strings.Split(string(output), "\n") {
485
-		parts := strings.Split(line, " ")
486
-		if len(parts) == 6 && parts[2] == "cgroup" {
487
-			for _, opt := range strings.Split(parts[3], ",") {
488
-				if opt == cgroupType {
489
-					return parts[1], nil
490
-				}
491
-			}
492
-		}
493
-	}
494
-
495
-	return "", fmt.Errorf("cgroup mountpoint not found for %s", cgroupType)
496
-}
497
-
498 7
 // Compare two Config struct. Do not compare the "Image" nor "Hostname" fields
499 8
 // If OpenStdin is set, then it differs
500 9
 func CompareConfig(a, b *Config) bool {
... ...
@@ -542,3 +51,7 @@ func CompareConfig(a, b *Config) bool {
542 542
 
543 543
 	return true
544 544
 }
545
+
546
+func GetKernelVersion() (*utils.KernelVersionInfo, error) {
547
+	return getKernelVersion()
548
+}
545 549
new file mode 100644
... ...
@@ -0,0 +1,470 @@
0
+package utils
1
+
2
+import (
3
+	"bytes"
4
+	"crypto/sha256"
5
+	"encoding/hex"
6
+	"errors"
7
+	"fmt"
8
+	"index/suffixarray"
9
+	"io"
10
+	"io/ioutil"
11
+	"net/http"
12
+	"os"
13
+	"os/exec"
14
+	"path/filepath"
15
+	"runtime"
16
+	"strings"
17
+	"sync"
18
+	"time"
19
+)
20
+
21
+// Go is a basic promise implementation: it wraps calls a function in a goroutine,
22
+// and returns a channel which will later return the function's return value.
23
+func Go(f func() error) chan error {
24
+	ch := make(chan error)
25
+	go func() {
26
+		ch <- f()
27
+	}()
28
+	return ch
29
+}
30
+
31
+// Request a given URL and return an io.Reader
32
+func Download(url string, stderr io.Writer) (*http.Response, error) {
33
+	var resp *http.Response
34
+	var err error = nil
35
+	if resp, err = http.Get(url); err != nil {
36
+		return nil, err
37
+	}
38
+	if resp.StatusCode >= 400 {
39
+		return nil, errors.New("Got HTTP status code >= 400: " + resp.Status)
40
+	}
41
+	return resp, nil
42
+}
43
+
44
+// Debug function, if the debug flag is set, then display. Do nothing otherwise
45
+// If Docker is in damon mode, also send the debug info on the socket
46
+func Debugf(format string, a ...interface{}) {
47
+	if os.Getenv("DEBUG") != "" {
48
+
49
+		// Retrieve the stack infos
50
+		_, file, line, ok := runtime.Caller(1)
51
+		if !ok {
52
+			file = "<unknown>"
53
+			line = -1
54
+		} else {
55
+			file = file[strings.LastIndex(file, "/")+1:]
56
+		}
57
+
58
+		fmt.Fprintf(os.Stderr, fmt.Sprintf("[debug] %s:%d %s\n", file, line, format), a...)
59
+	}
60
+}
61
+
62
+// Reader with progress bar
63
+type progressReader struct {
64
+	reader       io.ReadCloser // Stream to read from
65
+	output       io.Writer     // Where to send progress bar to
66
+	readTotal    int           // Expected stream length (bytes)
67
+	readProgress int           // How much has been read so far (bytes)
68
+	lastUpdate   int           // How many bytes read at least update
69
+	template     string        // Template to print. Default "%v/%v (%v)"
70
+}
71
+
72
+func (r *progressReader) Read(p []byte) (n int, err error) {
73
+	read, err := io.ReadCloser(r.reader).Read(p)
74
+	r.readProgress += read
75
+
76
+	updateEvery := 4096
77
+	if r.readTotal > 0 {
78
+		// Only update progress for every 1% read
79
+		if increment := int(0.01 * float64(r.readTotal)); increment > updateEvery {
80
+			updateEvery = increment
81
+		}
82
+	}
83
+	if r.readProgress-r.lastUpdate > updateEvery || err != nil {
84
+		if r.readTotal > 0 {
85
+			fmt.Fprintf(r.output, r.template+"\r", r.readProgress, r.readTotal, fmt.Sprintf("%.0f%%", float64(r.readProgress)/float64(r.readTotal)*100))
86
+		} else {
87
+			fmt.Fprintf(r.output, r.template+"\r", r.readProgress, "?", "n/a")
88
+		}
89
+		r.lastUpdate = r.readProgress
90
+	}
91
+	// Send newline when complete
92
+	if err != nil {
93
+		fmt.Fprintf(r.output, "\n")
94
+	}
95
+
96
+	return read, err
97
+}
98
+func (r *progressReader) Close() error {
99
+	return io.ReadCloser(r.reader).Close()
100
+}
101
+func ProgressReader(r io.ReadCloser, size int, output io.Writer, template string) *progressReader {
102
+	if template == "" {
103
+		template = "%v/%v (%v)"
104
+	}
105
+	return &progressReader{r, output, size, 0, 0, template}
106
+}
107
+
108
+// HumanDuration returns a human-readable approximation of a duration
109
+// (eg. "About a minute", "4 hours ago", etc.)
110
+func HumanDuration(d time.Duration) string {
111
+	if seconds := int(d.Seconds()); seconds < 1 {
112
+		return "Less than a second"
113
+	} else if seconds < 60 {
114
+		return fmt.Sprintf("%d seconds", seconds)
115
+	} else if minutes := int(d.Minutes()); minutes == 1 {
116
+		return "About a minute"
117
+	} else if minutes < 60 {
118
+		return fmt.Sprintf("%d minutes", minutes)
119
+	} else if hours := int(d.Hours()); hours == 1 {
120
+		return "About an hour"
121
+	} else if hours < 48 {
122
+		return fmt.Sprintf("%d hours", hours)
123
+	} else if hours < 24*7*2 {
124
+		return fmt.Sprintf("%d days", hours/24)
125
+	} else if hours < 24*30*3 {
126
+		return fmt.Sprintf("%d weeks", hours/24/7)
127
+	} else if hours < 24*365*2 {
128
+		return fmt.Sprintf("%d months", hours/24/30)
129
+	}
130
+	return fmt.Sprintf("%d years", d.Hours()/24/365)
131
+}
132
+
133
+func Trunc(s string, maxlen int) string {
134
+	if len(s) <= maxlen {
135
+		return s
136
+	}
137
+	return s[:maxlen]
138
+}
139
+
140
+// Figure out the absolute path of our own binary
141
+func SelfPath() string {
142
+	path, err := exec.LookPath(os.Args[0])
143
+	if err != nil {
144
+		panic(err)
145
+	}
146
+	path, err = filepath.Abs(path)
147
+	if err != nil {
148
+		panic(err)
149
+	}
150
+	return path
151
+}
152
+
153
+type nopWriter struct {
154
+}
155
+
156
+func (w *nopWriter) Write(buf []byte) (int, error) {
157
+	return len(buf), nil
158
+}
159
+
160
+type nopWriteCloser struct {
161
+	io.Writer
162
+}
163
+
164
+func (w *nopWriteCloser) Close() error { return nil }
165
+
166
+func NopWriteCloser(w io.Writer) io.WriteCloser {
167
+	return &nopWriteCloser{w}
168
+}
169
+
170
+type bufReader struct {
171
+	buf    *bytes.Buffer
172
+	reader io.Reader
173
+	err    error
174
+	l      sync.Mutex
175
+	wait   sync.Cond
176
+}
177
+
178
+func NewBufReader(r io.Reader) *bufReader {
179
+	reader := &bufReader{
180
+		buf:    &bytes.Buffer{},
181
+		reader: r,
182
+	}
183
+	reader.wait.L = &reader.l
184
+	go reader.drain()
185
+	return reader
186
+}
187
+
188
+func (r *bufReader) drain() {
189
+	buf := make([]byte, 1024)
190
+	for {
191
+		n, err := r.reader.Read(buf)
192
+		r.l.Lock()
193
+		if err != nil {
194
+			r.err = err
195
+		} else {
196
+			r.buf.Write(buf[0:n])
197
+		}
198
+		r.wait.Signal()
199
+		r.l.Unlock()
200
+		if err != nil {
201
+			break
202
+		}
203
+	}
204
+}
205
+
206
+func (r *bufReader) Read(p []byte) (n int, err error) {
207
+	r.l.Lock()
208
+	defer r.l.Unlock()
209
+	for {
210
+		n, err = r.buf.Read(p)
211
+		if n > 0 {
212
+			return n, err
213
+		}
214
+		if r.err != nil {
215
+			return 0, r.err
216
+		}
217
+		r.wait.Wait()
218
+	}
219
+	panic("unreachable")
220
+}
221
+
222
+func (r *bufReader) Close() error {
223
+	closer, ok := r.reader.(io.ReadCloser)
224
+	if !ok {
225
+		return nil
226
+	}
227
+	return closer.Close()
228
+}
229
+
230
+type WriteBroadcaster struct {
231
+	mu      sync.Mutex
232
+	writers map[io.WriteCloser]struct{}
233
+}
234
+
235
+func (w *WriteBroadcaster) AddWriter(writer io.WriteCloser) {
236
+	w.mu.Lock()
237
+	w.writers[writer] = struct{}{}
238
+	w.mu.Unlock()
239
+}
240
+
241
+// FIXME: Is that function used?
242
+// FIXME: This relies on the concrete writer type used having equality operator
243
+func (w *WriteBroadcaster) RemoveWriter(writer io.WriteCloser) {
244
+	w.mu.Lock()
245
+	delete(w.writers, writer)
246
+	w.mu.Unlock()
247
+}
248
+
249
+func (w *WriteBroadcaster) Write(p []byte) (n int, err error) {
250
+	w.mu.Lock()
251
+	defer w.mu.Unlock()
252
+	for writer := range w.writers {
253
+		if n, err := writer.Write(p); err != nil || n != len(p) {
254
+			// On error, evict the writer
255
+			delete(w.writers, writer)
256
+		}
257
+	}
258
+	return len(p), nil
259
+}
260
+
261
+func (w *WriteBroadcaster) CloseWriters() error {
262
+	w.mu.Lock()
263
+	defer w.mu.Unlock()
264
+	for writer := range w.writers {
265
+		writer.Close()
266
+	}
267
+	w.writers = make(map[io.WriteCloser]struct{})
268
+	return nil
269
+}
270
+
271
+func NewWriteBroadcaster() *WriteBroadcaster {
272
+	return &WriteBroadcaster{writers: make(map[io.WriteCloser]struct{})}
273
+}
274
+
275
+func GetTotalUsedFds() int {
276
+	if fds, err := ioutil.ReadDir(fmt.Sprintf("/proc/%d/fd", os.Getpid())); err != nil {
277
+		Debugf("Error opening /proc/%d/fd: %s", os.Getpid(), err)
278
+	} else {
279
+		return len(fds)
280
+	}
281
+	return -1
282
+}
283
+
284
+// TruncIndex allows the retrieval of string identifiers by any of their unique prefixes.
285
+// This is used to retrieve image and container IDs by more convenient shorthand prefixes.
286
+type TruncIndex struct {
287
+	index *suffixarray.Index
288
+	ids   map[string]bool
289
+	bytes []byte
290
+}
291
+
292
+func NewTruncIndex() *TruncIndex {
293
+	return &TruncIndex{
294
+		index: suffixarray.New([]byte{' '}),
295
+		ids:   make(map[string]bool),
296
+		bytes: []byte{' '},
297
+	}
298
+}
299
+
300
+func (idx *TruncIndex) Add(id string) error {
301
+	if strings.Contains(id, " ") {
302
+		return fmt.Errorf("Illegal character: ' '")
303
+	}
304
+	if _, exists := idx.ids[id]; exists {
305
+		return fmt.Errorf("Id already exists: %s", id)
306
+	}
307
+	idx.ids[id] = true
308
+	idx.bytes = append(idx.bytes, []byte(id+" ")...)
309
+	idx.index = suffixarray.New(idx.bytes)
310
+	return nil
311
+}
312
+
313
+func (idx *TruncIndex) Delete(id string) error {
314
+	if _, exists := idx.ids[id]; !exists {
315
+		return fmt.Errorf("No such id: %s", id)
316
+	}
317
+	before, after, err := idx.lookup(id)
318
+	if err != nil {
319
+		return err
320
+	}
321
+	delete(idx.ids, id)
322
+	idx.bytes = append(idx.bytes[:before], idx.bytes[after:]...)
323
+	idx.index = suffixarray.New(idx.bytes)
324
+	return nil
325
+}
326
+
327
+func (idx *TruncIndex) lookup(s string) (int, int, error) {
328
+	offsets := idx.index.Lookup([]byte(" "+s), -1)
329
+	//log.Printf("lookup(%s): %v (index bytes: '%s')\n", s, offsets, idx.index.Bytes())
330
+	if offsets == nil || len(offsets) == 0 || len(offsets) > 1 {
331
+		return -1, -1, fmt.Errorf("No such id: %s", s)
332
+	}
333
+	offsetBefore := offsets[0] + 1
334
+	offsetAfter := offsetBefore + strings.Index(string(idx.bytes[offsetBefore:]), " ")
335
+	return offsetBefore, offsetAfter, nil
336
+}
337
+
338
+func (idx *TruncIndex) Get(s string) (string, error) {
339
+	before, after, err := idx.lookup(s)
340
+	//log.Printf("Get(%s) bytes=|%s| before=|%d| after=|%d|\n", s, idx.bytes, before, after)
341
+	if err != nil {
342
+		return "", err
343
+	}
344
+	return string(idx.bytes[before:after]), err
345
+}
346
+
347
+// TruncateId returns a shorthand version of a string identifier for convenience.
348
+// A collision with other shorthands is very unlikely, but possible.
349
+// In case of a collision a lookup with TruncIndex.Get() will fail, and the caller
350
+// will need to use a langer prefix, or the full-length Id.
351
+func TruncateId(id string) string {
352
+	shortLen := 12
353
+	if len(id) < shortLen {
354
+		shortLen = len(id)
355
+	}
356
+	return id[:shortLen]
357
+}
358
+
359
+// Code c/c from io.Copy() modified to handle escape sequence
360
+func CopyEscapable(dst io.Writer, src io.ReadCloser) (written int64, err error) {
361
+	buf := make([]byte, 32*1024)
362
+	for {
363
+		nr, er := src.Read(buf)
364
+		if nr > 0 {
365
+			// ---- Docker addition
366
+			// char 16 is C-p
367
+			if nr == 1 && buf[0] == 16 {
368
+				nr, er = src.Read(buf)
369
+				// char 17 is C-q
370
+				if nr == 1 && buf[0] == 17 {
371
+					if err := src.Close(); err != nil {
372
+						return 0, err
373
+					}
374
+					return 0, io.EOF
375
+				}
376
+			}
377
+			// ---- End of docker
378
+			nw, ew := dst.Write(buf[0:nr])
379
+			if nw > 0 {
380
+				written += int64(nw)
381
+			}
382
+			if ew != nil {
383
+				err = ew
384
+				break
385
+			}
386
+			if nr != nw {
387
+				err = io.ErrShortWrite
388
+				break
389
+			}
390
+		}
391
+		if er == io.EOF {
392
+			break
393
+		}
394
+		if er != nil {
395
+			err = er
396
+			break
397
+		}
398
+	}
399
+	return written, err
400
+}
401
+
402
+func HashData(src io.Reader) (string, error) {
403
+	h := sha256.New()
404
+	if _, err := io.Copy(h, src); err != nil {
405
+		return "", err
406
+	}
407
+	return "sha256:" + hex.EncodeToString(h.Sum(nil)), nil
408
+}
409
+
410
+type KernelVersionInfo struct {
411
+	Kernel int
412
+	Major  int
413
+	Minor  int
414
+	Flavor string
415
+}
416
+
417
+func (k *KernelVersionInfo) String() string {
418
+	flavor := ""
419
+	if len(k.Flavor) > 0 {
420
+		flavor = fmt.Sprintf("-%s", k.Flavor)
421
+	}
422
+	return fmt.Sprintf("%d.%d.%d%s", k.Kernel, k.Major, k.Minor, flavor)
423
+}
424
+
425
+// Compare two KernelVersionInfo struct.
426
+// Returns -1 if a < b, = if a == b, 1 it a > b
427
+func CompareKernelVersion(a, b *KernelVersionInfo) int {
428
+	if a.Kernel < b.Kernel {
429
+		return -1
430
+	} else if a.Kernel > b.Kernel {
431
+		return 1
432
+	}
433
+
434
+	if a.Major < b.Major {
435
+		return -1
436
+	} else if a.Major > b.Major {
437
+		return 1
438
+	}
439
+
440
+	if a.Minor < b.Minor {
441
+		return -1
442
+	} else if a.Minor > b.Minor {
443
+		return 1
444
+	}
445
+
446
+	return 0
447
+}
448
+
449
+func FindCgroupMountpoint(cgroupType string) (string, error) {
450
+	output, err := ioutil.ReadFile("/proc/mounts")
451
+	if err != nil {
452
+		return "", err
453
+	}
454
+
455
+	// /proc/mounts has 6 fields per line, one mount per line, e.g.
456
+	// cgroup /sys/fs/cgroup/devices cgroup rw,relatime,devices 0 0
457
+	for _, line := range strings.Split(string(output), "\n") {
458
+		parts := strings.Split(line, " ")
459
+		if len(parts) == 6 && parts[2] == "cgroup" {
460
+			for _, opt := range strings.Split(parts[3], ",") {
461
+				if opt == cgroupType {
462
+					return parts[1], nil
463
+				}
464
+			}
465
+		}
466
+	}
467
+
468
+	return "", fmt.Errorf("cgroup mountpoint not found for %s", cgroupType)
469
+}
0 470
new file mode 100755
1 471
Binary files /dev/null and b/utils/utils.test differ
2 472
new file mode 100644
... ...
@@ -0,0 +1,263 @@
0
+package utils
1
+
2
+import (
3
+	"bytes"
4
+	"errors"
5
+	"io"
6
+	"io/ioutil"
7
+	"testing"
8
+)
9
+
10
+func TestBufReader(t *testing.T) {
11
+	reader, writer := io.Pipe()
12
+	bufreader := newBufReader(reader)
13
+
14
+	// Write everything down to a Pipe
15
+	// Usually, a pipe should block but because of the buffered reader,
16
+	// the writes will go through
17
+	done := make(chan bool)
18
+	go func() {
19
+		writer.Write([]byte("hello world"))
20
+		writer.Close()
21
+		done <- true
22
+	}()
23
+
24
+	// Drain the reader *after* everything has been written, just to verify
25
+	// it is indeed buffering
26
+	<-done
27
+	output, err := ioutil.ReadAll(bufreader)
28
+	if err != nil {
29
+		t.Fatal(err)
30
+	}
31
+	if !bytes.Equal(output, []byte("hello world")) {
32
+		t.Error(string(output))
33
+	}
34
+}
35
+
36
+type dummyWriter struct {
37
+	buffer      bytes.Buffer
38
+	failOnWrite bool
39
+}
40
+
41
+func (dw *dummyWriter) Write(p []byte) (n int, err error) {
42
+	if dw.failOnWrite {
43
+		return 0, errors.New("Fake fail")
44
+	}
45
+	return dw.buffer.Write(p)
46
+}
47
+
48
+func (dw *dummyWriter) String() string {
49
+	return dw.buffer.String()
50
+}
51
+
52
+func (dw *dummyWriter) Close() error {
53
+	return nil
54
+}
55
+
56
+func TestWriteBroadcaster(t *testing.T) {
57
+	writer := newWriteBroadcaster()
58
+
59
+	// Test 1: Both bufferA and bufferB should contain "foo"
60
+	bufferA := &dummyWriter{}
61
+	writer.AddWriter(bufferA)
62
+	bufferB := &dummyWriter{}
63
+	writer.AddWriter(bufferB)
64
+	writer.Write([]byte("foo"))
65
+
66
+	if bufferA.String() != "foo" {
67
+		t.Errorf("Buffer contains %v", bufferA.String())
68
+	}
69
+
70
+	if bufferB.String() != "foo" {
71
+		t.Errorf("Buffer contains %v", bufferB.String())
72
+	}
73
+
74
+	// Test2: bufferA and bufferB should contain "foobar",
75
+	// while bufferC should only contain "bar"
76
+	bufferC := &dummyWriter{}
77
+	writer.AddWriter(bufferC)
78
+	writer.Write([]byte("bar"))
79
+
80
+	if bufferA.String() != "foobar" {
81
+		t.Errorf("Buffer contains %v", bufferA.String())
82
+	}
83
+
84
+	if bufferB.String() != "foobar" {
85
+		t.Errorf("Buffer contains %v", bufferB.String())
86
+	}
87
+
88
+	if bufferC.String() != "bar" {
89
+		t.Errorf("Buffer contains %v", bufferC.String())
90
+	}
91
+
92
+	// Test3: Test removal
93
+	writer.RemoveWriter(bufferB)
94
+	writer.Write([]byte("42"))
95
+	if bufferA.String() != "foobar42" {
96
+		t.Errorf("Buffer contains %v", bufferA.String())
97
+	}
98
+	if bufferB.String() != "foobar" {
99
+		t.Errorf("Buffer contains %v", bufferB.String())
100
+	}
101
+	if bufferC.String() != "bar42" {
102
+		t.Errorf("Buffer contains %v", bufferC.String())
103
+	}
104
+
105
+	// Test4: Test eviction on failure
106
+	bufferA.failOnWrite = true
107
+	writer.Write([]byte("fail"))
108
+	if bufferA.String() != "foobar42" {
109
+		t.Errorf("Buffer contains %v", bufferA.String())
110
+	}
111
+	if bufferC.String() != "bar42fail" {
112
+		t.Errorf("Buffer contains %v", bufferC.String())
113
+	}
114
+	// Even though we reset the flag, no more writes should go in there
115
+	bufferA.failOnWrite = false
116
+	writer.Write([]byte("test"))
117
+	if bufferA.String() != "foobar42" {
118
+		t.Errorf("Buffer contains %v", bufferA.String())
119
+	}
120
+	if bufferC.String() != "bar42failtest" {
121
+		t.Errorf("Buffer contains %v", bufferC.String())
122
+	}
123
+
124
+	writer.CloseWriters()
125
+}
126
+
127
+type devNullCloser int
128
+
129
+func (d devNullCloser) Close() error {
130
+	return nil
131
+}
132
+
133
+func (d devNullCloser) Write(buf []byte) (int, error) {
134
+	return len(buf), nil
135
+}
136
+
137
+// This test checks for races. It is only useful when run with the race detector.
138
+func TestRaceWriteBroadcaster(t *testing.T) {
139
+	writer := newWriteBroadcaster()
140
+	c := make(chan bool)
141
+	go func() {
142
+		writer.AddWriter(devNullCloser(0))
143
+		c <- true
144
+	}()
145
+	writer.Write([]byte("hello"))
146
+	<-c
147
+}
148
+
149
+// Test the behavior of TruncIndex, an index for querying IDs from a non-conflicting prefix.
150
+func TestTruncIndex(t *testing.T) {
151
+	index := NewTruncIndex()
152
+	// Get on an empty index
153
+	if _, err := index.Get("foobar"); err == nil {
154
+		t.Fatal("Get on an empty index should return an error")
155
+	}
156
+
157
+	// Spaces should be illegal in an id
158
+	if err := index.Add("I have a space"); err == nil {
159
+		t.Fatalf("Adding an id with ' ' should return an error")
160
+	}
161
+
162
+	id := "99b36c2c326ccc11e726eee6ee78a0baf166ef96"
163
+	// Add an id
164
+	if err := index.Add(id); err != nil {
165
+		t.Fatal(err)
166
+	}
167
+	// Get a non-existing id
168
+	assertIndexGet(t, index, "abracadabra", "", true)
169
+	// Get the exact id
170
+	assertIndexGet(t, index, id, id, false)
171
+	// The first letter should match
172
+	assertIndexGet(t, index, id[:1], id, false)
173
+	// The first half should match
174
+	assertIndexGet(t, index, id[:len(id)/2], id, false)
175
+	// The second half should NOT match
176
+	assertIndexGet(t, index, id[len(id)/2:], "", true)
177
+
178
+	id2 := id[:6] + "blabla"
179
+	// Add an id
180
+	if err := index.Add(id2); err != nil {
181
+		t.Fatal(err)
182
+	}
183
+	// Both exact IDs should work
184
+	assertIndexGet(t, index, id, id, false)
185
+	assertIndexGet(t, index, id2, id2, false)
186
+
187
+	// 6 characters or less should conflict
188
+	assertIndexGet(t, index, id[:6], "", true)
189
+	assertIndexGet(t, index, id[:4], "", true)
190
+	assertIndexGet(t, index, id[:1], "", true)
191
+
192
+	// 7 characters should NOT conflict
193
+	assertIndexGet(t, index, id[:7], id, false)
194
+	assertIndexGet(t, index, id2[:7], id2, false)
195
+
196
+	// Deleting a non-existing id should return an error
197
+	if err := index.Delete("non-existing"); err == nil {
198
+		t.Fatalf("Deleting a non-existing id should return an error")
199
+	}
200
+
201
+	// Deleting id2 should remove conflicts
202
+	if err := index.Delete(id2); err != nil {
203
+		t.Fatal(err)
204
+	}
205
+	// id2 should no longer work
206
+	assertIndexGet(t, index, id2, "", true)
207
+	assertIndexGet(t, index, id2[:7], "", true)
208
+	assertIndexGet(t, index, id2[:11], "", true)
209
+
210
+	// conflicts between id and id2 should be gone
211
+	assertIndexGet(t, index, id[:6], id, false)
212
+	assertIndexGet(t, index, id[:4], id, false)
213
+	assertIndexGet(t, index, id[:1], id, false)
214
+
215
+	// non-conflicting substrings should still not conflict
216
+	assertIndexGet(t, index, id[:7], id, false)
217
+	assertIndexGet(t, index, id[:15], id, false)
218
+	assertIndexGet(t, index, id, id, false)
219
+}
220
+
221
+func assertIndexGet(t *testing.T, index *TruncIndex, input, expectedResult string, expectError bool) {
222
+	if result, err := index.Get(input); err != nil && !expectError {
223
+		t.Fatalf("Unexpected error getting '%s': %s", input, err)
224
+	} else if err == nil && expectError {
225
+		t.Fatalf("Getting '%s' should return an error", input)
226
+	} else if result != expectedResult {
227
+		t.Fatalf("Getting '%s' returned '%s' instead of '%s'", input, result, expectedResult)
228
+	}
229
+}
230
+
231
+func assertKernelVersion(t *testing.T, a, b *KernelVersionInfo, result int) {
232
+	if r := CompareKernelVersion(a, b); r != result {
233
+		t.Fatalf("Unepected kernel version comparaison result. Found %d, expected %d", r, result)
234
+	}
235
+}
236
+
237
+func TestCompareKernelVersion(t *testing.T) {
238
+	assertKernelVersion(t,
239
+		&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
240
+		&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
241
+		0)
242
+	assertKernelVersion(t,
243
+		&KernelVersionInfo{Kernel: 2, Major: 6, Minor: 0},
244
+		&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
245
+		-1)
246
+	assertKernelVersion(t,
247
+		&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
248
+		&KernelVersionInfo{Kernel: 2, Major: 6, Minor: 0},
249
+		1)
250
+	assertKernelVersion(t,
251
+		&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0, Flavor: "0"},
252
+		&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0, Flavor: "16"},
253
+		0)
254
+	assertKernelVersion(t,
255
+		&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 5},
256
+		&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
257
+		1)
258
+	assertKernelVersion(t,
259
+		&KernelVersionInfo{Kernel: 3, Major: 0, Minor: 20, Flavor: "25"},
260
+		&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0, Flavor: "0"},
261
+		-1)
262
+}
0 263
deleted file mode 100644
... ...
@@ -1,263 +0,0 @@
1
-package docker
2
-
3
-import (
4
-	"bytes"
5
-	"errors"
6
-	"io"
7
-	"io/ioutil"
8
-	"testing"
9
-)
10
-
11
-func TestBufReader(t *testing.T) {
12
-	reader, writer := io.Pipe()
13
-	bufreader := newBufReader(reader)
14
-
15
-	// Write everything down to a Pipe
16
-	// Usually, a pipe should block but because of the buffered reader,
17
-	// the writes will go through
18
-	done := make(chan bool)
19
-	go func() {
20
-		writer.Write([]byte("hello world"))
21
-		writer.Close()
22
-		done <- true
23
-	}()
24
-
25
-	// Drain the reader *after* everything has been written, just to verify
26
-	// it is indeed buffering
27
-	<-done
28
-	output, err := ioutil.ReadAll(bufreader)
29
-	if err != nil {
30
-		t.Fatal(err)
31
-	}
32
-	if !bytes.Equal(output, []byte("hello world")) {
33
-		t.Error(string(output))
34
-	}
35
-}
36
-
37
-type dummyWriter struct {
38
-	buffer      bytes.Buffer
39
-	failOnWrite bool
40
-}
41
-
42
-func (dw *dummyWriter) Write(p []byte) (n int, err error) {
43
-	if dw.failOnWrite {
44
-		return 0, errors.New("Fake fail")
45
-	}
46
-	return dw.buffer.Write(p)
47
-}
48
-
49
-func (dw *dummyWriter) String() string {
50
-	return dw.buffer.String()
51
-}
52
-
53
-func (dw *dummyWriter) Close() error {
54
-	return nil
55
-}
56
-
57
-func TestWriteBroadcaster(t *testing.T) {
58
-	writer := newWriteBroadcaster()
59
-
60
-	// Test 1: Both bufferA and bufferB should contain "foo"
61
-	bufferA := &dummyWriter{}
62
-	writer.AddWriter(bufferA)
63
-	bufferB := &dummyWriter{}
64
-	writer.AddWriter(bufferB)
65
-	writer.Write([]byte("foo"))
66
-
67
-	if bufferA.String() != "foo" {
68
-		t.Errorf("Buffer contains %v", bufferA.String())
69
-	}
70
-
71
-	if bufferB.String() != "foo" {
72
-		t.Errorf("Buffer contains %v", bufferB.String())
73
-	}
74
-
75
-	// Test2: bufferA and bufferB should contain "foobar",
76
-	// while bufferC should only contain "bar"
77
-	bufferC := &dummyWriter{}
78
-	writer.AddWriter(bufferC)
79
-	writer.Write([]byte("bar"))
80
-
81
-	if bufferA.String() != "foobar" {
82
-		t.Errorf("Buffer contains %v", bufferA.String())
83
-	}
84
-
85
-	if bufferB.String() != "foobar" {
86
-		t.Errorf("Buffer contains %v", bufferB.String())
87
-	}
88
-
89
-	if bufferC.String() != "bar" {
90
-		t.Errorf("Buffer contains %v", bufferC.String())
91
-	}
92
-
93
-	// Test3: Test removal
94
-	writer.RemoveWriter(bufferB)
95
-	writer.Write([]byte("42"))
96
-	if bufferA.String() != "foobar42" {
97
-		t.Errorf("Buffer contains %v", bufferA.String())
98
-	}
99
-	if bufferB.String() != "foobar" {
100
-		t.Errorf("Buffer contains %v", bufferB.String())
101
-	}
102
-	if bufferC.String() != "bar42" {
103
-		t.Errorf("Buffer contains %v", bufferC.String())
104
-	}
105
-
106
-	// Test4: Test eviction on failure
107
-	bufferA.failOnWrite = true
108
-	writer.Write([]byte("fail"))
109
-	if bufferA.String() != "foobar42" {
110
-		t.Errorf("Buffer contains %v", bufferA.String())
111
-	}
112
-	if bufferC.String() != "bar42fail" {
113
-		t.Errorf("Buffer contains %v", bufferC.String())
114
-	}
115
-	// Even though we reset the flag, no more writes should go in there
116
-	bufferA.failOnWrite = false
117
-	writer.Write([]byte("test"))
118
-	if bufferA.String() != "foobar42" {
119
-		t.Errorf("Buffer contains %v", bufferA.String())
120
-	}
121
-	if bufferC.String() != "bar42failtest" {
122
-		t.Errorf("Buffer contains %v", bufferC.String())
123
-	}
124
-
125
-	writer.CloseWriters()
126
-}
127
-
128
-type devNullCloser int
129
-
130
-func (d devNullCloser) Close() error {
131
-	return nil
132
-}
133
-
134
-func (d devNullCloser) Write(buf []byte) (int, error) {
135
-	return len(buf), nil
136
-}
137
-
138
-// This test checks for races. It is only useful when run with the race detector.
139
-func TestRaceWriteBroadcaster(t *testing.T) {
140
-	writer := newWriteBroadcaster()
141
-	c := make(chan bool)
142
-	go func() {
143
-		writer.AddWriter(devNullCloser(0))
144
-		c <- true
145
-	}()
146
-	writer.Write([]byte("hello"))
147
-	<-c
148
-}
149
-
150
-// Test the behavior of TruncIndex, an index for querying IDs from a non-conflicting prefix.
151
-func TestTruncIndex(t *testing.T) {
152
-	index := NewTruncIndex()
153
-	// Get on an empty index
154
-	if _, err := index.Get("foobar"); err == nil {
155
-		t.Fatal("Get on an empty index should return an error")
156
-	}
157
-
158
-	// Spaces should be illegal in an id
159
-	if err := index.Add("I have a space"); err == nil {
160
-		t.Fatalf("Adding an id with ' ' should return an error")
161
-	}
162
-
163
-	id := "99b36c2c326ccc11e726eee6ee78a0baf166ef96"
164
-	// Add an id
165
-	if err := index.Add(id); err != nil {
166
-		t.Fatal(err)
167
-	}
168
-	// Get a non-existing id
169
-	assertIndexGet(t, index, "abracadabra", "", true)
170
-	// Get the exact id
171
-	assertIndexGet(t, index, id, id, false)
172
-	// The first letter should match
173
-	assertIndexGet(t, index, id[:1], id, false)
174
-	// The first half should match
175
-	assertIndexGet(t, index, id[:len(id)/2], id, false)
176
-	// The second half should NOT match
177
-	assertIndexGet(t, index, id[len(id)/2:], "", true)
178
-
179
-	id2 := id[:6] + "blabla"
180
-	// Add an id
181
-	if err := index.Add(id2); err != nil {
182
-		t.Fatal(err)
183
-	}
184
-	// Both exact IDs should work
185
-	assertIndexGet(t, index, id, id, false)
186
-	assertIndexGet(t, index, id2, id2, false)
187
-
188
-	// 6 characters or less should conflict
189
-	assertIndexGet(t, index, id[:6], "", true)
190
-	assertIndexGet(t, index, id[:4], "", true)
191
-	assertIndexGet(t, index, id[:1], "", true)
192
-
193
-	// 7 characters should NOT conflict
194
-	assertIndexGet(t, index, id[:7], id, false)
195
-	assertIndexGet(t, index, id2[:7], id2, false)
196
-
197
-	// Deleting a non-existing id should return an error
198
-	if err := index.Delete("non-existing"); err == nil {
199
-		t.Fatalf("Deleting a non-existing id should return an error")
200
-	}
201
-
202
-	// Deleting id2 should remove conflicts
203
-	if err := index.Delete(id2); err != nil {
204
-		t.Fatal(err)
205
-	}
206
-	// id2 should no longer work
207
-	assertIndexGet(t, index, id2, "", true)
208
-	assertIndexGet(t, index, id2[:7], "", true)
209
-	assertIndexGet(t, index, id2[:11], "", true)
210
-
211
-	// conflicts between id and id2 should be gone
212
-	assertIndexGet(t, index, id[:6], id, false)
213
-	assertIndexGet(t, index, id[:4], id, false)
214
-	assertIndexGet(t, index, id[:1], id, false)
215
-
216
-	// non-conflicting substrings should still not conflict
217
-	assertIndexGet(t, index, id[:7], id, false)
218
-	assertIndexGet(t, index, id[:15], id, false)
219
-	assertIndexGet(t, index, id, id, false)
220
-}
221
-
222
-func assertIndexGet(t *testing.T, index *TruncIndex, input, expectedResult string, expectError bool) {
223
-	if result, err := index.Get(input); err != nil && !expectError {
224
-		t.Fatalf("Unexpected error getting '%s': %s", input, err)
225
-	} else if err == nil && expectError {
226
-		t.Fatalf("Getting '%s' should return an error", input)
227
-	} else if result != expectedResult {
228
-		t.Fatalf("Getting '%s' returned '%s' instead of '%s'", input, result, expectedResult)
229
-	}
230
-}
231
-
232
-func assertKernelVersion(t *testing.T, a, b *KernelVersionInfo, result int) {
233
-	if r := CompareKernelVersion(a, b); r != result {
234
-		t.Fatalf("Unepected kernel version comparaison result. Found %d, expected %d", r, result)
235
-	}
236
-}
237
-
238
-func TestCompareKernelVersion(t *testing.T) {
239
-	assertKernelVersion(t,
240
-		&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
241
-		&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
242
-		0)
243
-	assertKernelVersion(t,
244
-		&KernelVersionInfo{Kernel: 2, Major: 6, Minor: 0},
245
-		&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
246
-		-1)
247
-	assertKernelVersion(t,
248
-		&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
249
-		&KernelVersionInfo{Kernel: 2, Major: 6, Minor: 0},
250
-		1)
251
-	assertKernelVersion(t,
252
-		&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0, Flavor: "0"},
253
-		&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0, Flavor: "16"},
254
-		0)
255
-	assertKernelVersion(t,
256
-		&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 5},
257
-		&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
258
-		1)
259
-	assertKernelVersion(t,
260
-		&KernelVersionInfo{Kernel: 3, Major: 0, Minor: 20, Flavor: "25"},
261
-		&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0, Flavor: "0"},
262
-		-1)
263
-}