| ... | ... |
@@ -1,8 +1,8 @@ |
| 1 | 1 |
package client |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
- "github.com/dotcloud/docker/rcli" |
|
| 5 | 4 |
"github.com/dotcloud/docker/future" |
| 5 |
+ "github.com/dotcloud/docker/rcli" |
|
| 6 | 6 |
"io" |
| 7 | 7 |
"io/ioutil" |
| 8 | 8 |
"log" |
| ... | ... |
@@ -112,7 +112,7 @@ func InteractiveMode(scripts ...string) error {
|
| 112 | 112 |
return err |
| 113 | 113 |
} |
| 114 | 114 |
io.WriteString(rcfile, "enable -n help\n") |
| 115 |
- os.Setenv("PATH", tmp + ":" + os.Getenv("PATH"))
|
|
| 115 |
+ os.Setenv("PATH", tmp+":"+os.Getenv("PATH"))
|
|
| 116 | 116 |
os.Setenv("PS1", "\\h docker> ")
|
| 117 | 117 |
shell := exec.Command("/bin/bash", append([]string{"--rcfile", rcfile.Name()}, scripts...)...)
|
| 118 | 118 |
shell.Stdin = os.Stdin |
| ... | ... |
@@ -15,7 +15,6 @@ type Termios struct {
|
| 15 | 15 |
Ospeed uintptr |
| 16 | 16 |
} |
| 17 | 17 |
|
| 18 |
- |
|
| 19 | 18 |
const ( |
| 20 | 19 |
// Input flags |
| 21 | 20 |
inpck = 0x010 |
| ... | ... |
@@ -35,113 +34,110 @@ const ( |
| 35 | 35 |
) |
| 36 | 36 |
|
| 37 | 37 |
const ( |
| 38 |
- HUPCL = 0x4000 |
|
| 39 |
- ICANON = 0x100 |
|
| 40 |
- ICRNL = 0x100 |
|
| 41 |
- IEXTEN = 0x400 |
|
| 42 |
- BRKINT = 0x2 |
|
| 43 |
- CFLUSH = 0xf |
|
| 44 |
- CLOCAL = 0x8000 |
|
| 45 |
- CREAD = 0x800 |
|
| 46 |
- CS5 = 0x0 |
|
| 47 |
- CS6 = 0x100 |
|
| 48 |
- CS7 = 0x200 |
|
| 49 |
- CS8 = 0x300 |
|
| 50 |
- CSIZE = 0x300 |
|
| 51 |
- CSTART = 0x11 |
|
| 52 |
- CSTATUS = 0x14 |
|
| 53 |
- CSTOP = 0x13 |
|
| 54 |
- CSTOPB = 0x400 |
|
| 55 |
- CSUSP = 0x1a |
|
| 56 |
- IGNBRK = 0x1 |
|
| 57 |
- IGNCR = 0x80 |
|
| 58 |
- IGNPAR = 0x4 |
|
| 59 |
- IMAXBEL = 0x2000 |
|
| 60 |
- INLCR = 0x40 |
|
| 61 |
- INPCK = 0x10 |
|
| 62 |
- ISIG = 0x80 |
|
| 63 |
- ISTRIP = 0x20 |
|
| 64 |
- IUTF8 = 0x4000 |
|
| 65 |
- IXANY = 0x800 |
|
| 66 |
- IXOFF = 0x400 |
|
| 67 |
- IXON = 0x200 |
|
| 68 |
- NOFLSH = 0x80000000 |
|
| 69 |
- OCRNL = 0x10 |
|
| 70 |
- OFDEL = 0x20000 |
|
| 71 |
- OFILL = 0x80 |
|
| 72 |
- ONLCR = 0x2 |
|
| 73 |
- ONLRET = 0x40 |
|
| 74 |
- ONOCR = 0x20 |
|
| 75 |
- ONOEOT = 0x8 |
|
| 76 |
- OPOST = 0x1 |
|
| 77 |
-RENB = 0x1000 |
|
| 78 |
- PARMRK = 0x8 |
|
| 79 |
- PARODD = 0x2000 |
|
| 80 |
- |
|
| 81 |
- TOSTOP = 0x400000 |
|
| 82 |
- VDISCARD = 0xf |
|
| 83 |
- VDSUSP = 0xb |
|
| 84 |
- VEOF = 0x0 |
|
| 85 |
- VEOL = 0x1 |
|
| 86 |
- VEOL2 = 0x2 |
|
| 87 |
- VERASE = 0x3 |
|
| 88 |
- VINTR = 0x8 |
|
| 89 |
- VKILL = 0x5 |
|
| 90 |
- VLNEXT = 0xe |
|
| 91 |
- VMIN = 0x10 |
|
| 92 |
- VQUIT = 0x9 |
|
| 93 |
- VREPRINT = 0x6 |
|
| 94 |
- VSTART = 0xc |
|
| 95 |
- VSTATUS = 0x12 |
|
| 96 |
- VSTOP = 0xd |
|
| 97 |
- VSUSP = 0xa |
|
| 98 |
- VT0 = 0x0 |
|
| 99 |
- VT1 = 0x10000 |
|
| 100 |
- VTDLY = 0x10000 |
|
| 101 |
- VTIME = 0x11 |
|
| 102 |
- ECHO = 0x00000008 |
|
| 103 |
- |
|
| 104 |
- PENDIN = 0x20000000 |
|
| 38 |
+ HUPCL = 0x4000 |
|
| 39 |
+ ICANON = 0x100 |
|
| 40 |
+ ICRNL = 0x100 |
|
| 41 |
+ IEXTEN = 0x400 |
|
| 42 |
+ BRKINT = 0x2 |
|
| 43 |
+ CFLUSH = 0xf |
|
| 44 |
+ CLOCAL = 0x8000 |
|
| 45 |
+ CREAD = 0x800 |
|
| 46 |
+ CS5 = 0x0 |
|
| 47 |
+ CS6 = 0x100 |
|
| 48 |
+ CS7 = 0x200 |
|
| 49 |
+ CS8 = 0x300 |
|
| 50 |
+ CSIZE = 0x300 |
|
| 51 |
+ CSTART = 0x11 |
|
| 52 |
+ CSTATUS = 0x14 |
|
| 53 |
+ CSTOP = 0x13 |
|
| 54 |
+ CSTOPB = 0x400 |
|
| 55 |
+ CSUSP = 0x1a |
|
| 56 |
+ IGNBRK = 0x1 |
|
| 57 |
+ IGNCR = 0x80 |
|
| 58 |
+ IGNPAR = 0x4 |
|
| 59 |
+ IMAXBEL = 0x2000 |
|
| 60 |
+ INLCR = 0x40 |
|
| 61 |
+ INPCK = 0x10 |
|
| 62 |
+ ISIG = 0x80 |
|
| 63 |
+ ISTRIP = 0x20 |
|
| 64 |
+ IUTF8 = 0x4000 |
|
| 65 |
+ IXANY = 0x800 |
|
| 66 |
+ IXOFF = 0x400 |
|
| 67 |
+ IXON = 0x200 |
|
| 68 |
+ NOFLSH = 0x80000000 |
|
| 69 |
+ OCRNL = 0x10 |
|
| 70 |
+ OFDEL = 0x20000 |
|
| 71 |
+ OFILL = 0x80 |
|
| 72 |
+ ONLCR = 0x2 |
|
| 73 |
+ ONLRET = 0x40 |
|
| 74 |
+ ONOCR = 0x20 |
|
| 75 |
+ ONOEOT = 0x8 |
|
| 76 |
+ OPOST = 0x1 |
|
| 77 |
+ RENB = 0x1000 |
|
| 78 |
+ PARMRK = 0x8 |
|
| 79 |
+ PARODD = 0x2000 |
|
| 80 |
+ |
|
| 81 |
+ TOSTOP = 0x400000 |
|
| 82 |
+ VDISCARD = 0xf |
|
| 83 |
+ VDSUSP = 0xb |
|
| 84 |
+ VEOF = 0x0 |
|
| 85 |
+ VEOL = 0x1 |
|
| 86 |
+ VEOL2 = 0x2 |
|
| 87 |
+ VERASE = 0x3 |
|
| 88 |
+ VINTR = 0x8 |
|
| 89 |
+ VKILL = 0x5 |
|
| 90 |
+ VLNEXT = 0xe |
|
| 91 |
+ VMIN = 0x10 |
|
| 92 |
+ VQUIT = 0x9 |
|
| 93 |
+ VREPRINT = 0x6 |
|
| 94 |
+ VSTART = 0xc |
|
| 95 |
+ VSTATUS = 0x12 |
|
| 96 |
+ VSTOP = 0xd |
|
| 97 |
+ VSUSP = 0xa |
|
| 98 |
+ VT0 = 0x0 |
|
| 99 |
+ VT1 = 0x10000 |
|
| 100 |
+ VTDLY = 0x10000 |
|
| 101 |
+ VTIME = 0x11 |
|
| 102 |
+ ECHO = 0x00000008 |
|
| 103 |
+ |
|
| 104 |
+ PENDIN = 0x20000000 |
|
| 105 | 105 |
) |
| 106 | 106 |
|
| 107 | 107 |
type State struct {
|
| 108 |
- termios Termios |
|
| 108 |
+ termios Termios |
|
| 109 | 109 |
} |
| 110 | 110 |
|
| 111 | 111 |
// IsTerminal returns true if the given file descriptor is a terminal. |
| 112 | 112 |
func IsTerminal(fd int) bool {
|
| 113 |
- var termios Termios |
|
| 114 |
- _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(getTermios), uintptr(unsafe.Pointer(&termios)), 0, 0, 0) |
|
| 115 |
- return err == 0 |
|
| 113 |
+ var termios Termios |
|
| 114 |
+ _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(getTermios), uintptr(unsafe.Pointer(&termios)), 0, 0, 0) |
|
| 115 |
+ return err == 0 |
|
| 116 | 116 |
} |
| 117 | 117 |
|
| 118 | 118 |
// MakeRaw put the terminal connected to the given file descriptor into raw |
| 119 | 119 |
// mode and returns the previous state of the terminal so that it can be |
| 120 | 120 |
// restored. |
| 121 | 121 |
func MakeRaw(fd int) (*State, error) {
|
| 122 |
- var oldState State |
|
| 123 |
- if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(getTermios), uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 {
|
|
| 124 |
- return nil, err |
|
| 125 |
- } |
|
| 126 |
- |
|
| 127 |
- newState := oldState.termios |
|
| 128 |
- newState.Iflag &^= ISTRIP | INLCR | IGNCR | IXON | IXOFF |
|
| 129 |
- newState.Iflag |= ICRNL |
|
| 130 |
- newState.Oflag |= ONLCR |
|
| 131 |
- newState.Lflag &^= ECHO | ICANON | ISIG |
|
| 132 |
- if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(setTermios), uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
|
|
| 133 |
- return nil, err |
|
| 134 |
- } |
|
| 135 |
- |
|
| 136 |
- return &oldState, nil |
|
| 122 |
+ var oldState State |
|
| 123 |
+ if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(getTermios), uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 {
|
|
| 124 |
+ return nil, err |
|
| 125 |
+ } |
|
| 126 |
+ |
|
| 127 |
+ newState := oldState.termios |
|
| 128 |
+ newState.Iflag &^= ISTRIP | INLCR | IGNCR | IXON | IXOFF |
|
| 129 |
+ newState.Iflag |= ICRNL |
|
| 130 |
+ newState.Oflag |= ONLCR |
|
| 131 |
+ newState.Lflag &^= ECHO | ICANON | ISIG |
|
| 132 |
+ if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(setTermios), uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
|
|
| 133 |
+ return nil, err |
|
| 134 |
+ } |
|
| 135 |
+ |
|
| 136 |
+ return &oldState, nil |
|
| 137 | 137 |
} |
| 138 | 138 |
|
| 139 |
- |
|
| 140 | 139 |
// Restore restores the terminal connected to the given file descriptor to a |
| 141 | 140 |
// previous state. |
| 142 | 141 |
func Restore(fd int, state *State) error {
|
| 143 |
- _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(setTermios), uintptr(unsafe.Pointer(&state.termios)), 0, 0, 0) |
|
| 144 |
- return err |
|
| 142 |
+ _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(setTermios), uintptr(unsafe.Pointer(&state.termios)), 0, 0, 0) |
|
| 143 |
+ return err |
|
| 145 | 144 |
} |
| 146 |
- |
|
| 147 |
- |
| ... | ... |
@@ -1,6 +1,7 @@ |
| 1 | 1 |
package docker |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "./fs" |
|
| 4 | 5 |
"bytes" |
| 5 | 6 |
"encoding/json" |
| 6 | 7 |
"errors" |
| ... | ... |
@@ -14,7 +15,6 @@ import ( |
| 14 | 14 |
"strings" |
| 15 | 15 |
"syscall" |
| 16 | 16 |
"time" |
| 17 |
- "./fs" |
|
| 18 | 17 |
) |
| 19 | 18 |
|
| 20 | 19 |
var sysInitPath string |
| ... | ... |
@@ -35,7 +35,7 @@ type Container struct {
|
| 35 | 35 |
Config *Config |
| 36 | 36 |
Mountpoint *fs.Mountpoint |
| 37 | 37 |
State *State |
| 38 |
- Image string |
|
| 38 |
+ Image string |
|
| 39 | 39 |
|
| 40 | 40 |
SysInitPath string |
| 41 | 41 |
lxcConfigPath string |
| ... | ... |
@@ -69,7 +69,7 @@ func createContainer(id string, root string, command string, args []string, imag |
| 69 | 69 |
Path: command, |
| 70 | 70 |
Args: args, |
| 71 | 71 |
Config: config, |
| 72 |
- Image: image.Id, |
|
| 72 |
+ Image: image.Id, |
|
| 73 | 73 |
Mountpoint: mountpoint, |
| 74 | 74 |
State: newState(), |
| 75 | 75 |
|
| ... | ... |
@@ -1,6 +1,7 @@ |
| 1 | 1 |
package docker |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "./fs" |
|
| 4 | 5 |
"container/list" |
| 5 | 6 |
"fmt" |
| 6 | 7 |
"io/ioutil" |
| ... | ... |
@@ -8,14 +9,13 @@ import ( |
| 8 | 8 |
"os" |
| 9 | 9 |
"path" |
| 10 | 10 |
"sort" |
| 11 |
- "./fs" |
|
| 12 | 11 |
) |
| 13 | 12 |
|
| 14 | 13 |
type Docker struct {
|
| 15 |
- root string |
|
| 16 |
- repository string |
|
| 17 |
- containers *list.List |
|
| 18 |
- Store *fs.Store |
|
| 14 |
+ root string |
|
| 15 |
+ repository string |
|
| 16 |
+ containers *list.List |
|
| 17 |
+ Store *fs.Store |
|
| 19 | 18 |
} |
| 20 | 19 |
|
| 21 | 20 |
func (docker *Docker) List() []*Container {
|
| ... | ... |
@@ -117,7 +117,7 @@ func NewFromDirectory(root string) (*Docker, error) {
|
| 117 | 117 |
root: root, |
| 118 | 118 |
repository: path.Join(root, "containers"), |
| 119 | 119 |
containers: list.New(), |
| 120 |
- Store: store, |
|
| 120 |
+ Store: store, |
|
| 121 | 121 |
} |
| 122 | 122 |
|
| 123 | 123 |
if err := os.MkdirAll(docker.repository, 0700); err != nil && !os.IsExist(err) {
|
| ... | ... |
@@ -1,17 +1,17 @@ |
| 1 | 1 |
package docker |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "./fs" |
|
| 5 |
+ "io" |
|
| 4 | 6 |
"io/ioutil" |
| 5 | 7 |
"log" |
| 6 | 8 |
"os" |
| 7 | 9 |
"testing" |
| 8 |
- "io" |
|
| 9 |
- "./fs" |
|
| 10 | 10 |
) |
| 11 | 11 |
|
| 12 | 12 |
const testLayerPath string = "/var/lib/docker/docker-ut.tar" |
| 13 | 13 |
|
| 14 |
-func layerArchive(tarfile string) (io.Reader, error) {
|
|
| 14 |
+func layerArchive(tarfile string) (io.Reader, error) {
|
|
| 15 | 15 |
// FIXME: need to close f somewhere |
| 16 | 16 |
f, err := os.Open(tarfile) |
| 17 | 17 |
if err != nil {
|
| ... | ... |
@@ -57,7 +57,7 @@ func newTestDocker() (*Docker, error) {
|
| 57 | 57 |
return docker, nil |
| 58 | 58 |
} |
| 59 | 59 |
|
| 60 |
-func GetTestImage(docker *Docker) (*fs.Image) {
|
|
| 60 |
+func GetTestImage(docker *Docker) *fs.Image {
|
|
| 61 | 61 |
imgs, err := docker.Store.Images() |
| 62 | 62 |
if err != nil {
|
| 63 | 63 |
panic(err) |
| ... | ... |
@@ -1,20 +1,19 @@ |
| 1 | 1 |
package fake |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "archive/tar" |
|
| 4 | 5 |
"bytes" |
| 5 |
- "math/rand" |
|
| 6 |
+ "github.com/kr/pty" |
|
| 6 | 7 |
"io" |
| 7 |
- "archive/tar" |
|
| 8 |
+ "math/rand" |
|
| 8 | 9 |
"os/exec" |
| 9 |
- "github.com/kr/pty" |
|
| 10 | 10 |
) |
| 11 | 11 |
|
| 12 |
- |
|
| 13 | 12 |
func FakeTar() (io.Reader, error) {
|
| 14 | 13 |
content := []byte("Hello world!\n")
|
| 15 | 14 |
buf := new(bytes.Buffer) |
| 16 | 15 |
tw := tar.NewWriter(buf) |
| 17 |
- for _, name := range []string {"/etc/postgres/postgres.conf", "/etc/passwd", "/var/log/postgres/postgres.conf"} {
|
|
| 16 |
+ for _, name := range []string{"/etc/postgres/postgres.conf", "/etc/passwd", "/var/log/postgres/postgres.conf"} {
|
|
| 18 | 17 |
hdr := new(tar.Header) |
| 19 | 18 |
hdr.Size = int64(len(content)) |
| 20 | 19 |
hdr.Name = name |
| ... | ... |
@@ -27,7 +26,6 @@ func FakeTar() (io.Reader, error) {
|
| 27 | 27 |
return buf, nil |
| 28 | 28 |
} |
| 29 | 29 |
|
| 30 |
- |
|
| 31 | 30 |
func WriteFakeTar(dst io.Writer) error {
|
| 32 | 31 |
if data, err := FakeTar(); err != nil {
|
| 33 | 32 |
return err |
| ... | ... |
@@ -37,7 +35,6 @@ func WriteFakeTar(dst io.Writer) error {
|
| 37 | 37 |
return nil |
| 38 | 38 |
} |
| 39 | 39 |
|
| 40 |
- |
|
| 41 | 40 |
func RandomBytesChanged() uint {
|
| 42 | 41 |
return uint(rand.Int31n(24 * 1024 * 1024)) |
| 43 | 42 |
} |
| ... | ... |
@@ -54,7 +51,6 @@ func ContainerRunning() bool {
|
| 54 | 54 |
return false |
| 55 | 55 |
} |
| 56 | 56 |
|
| 57 |
- |
|
| 58 | 57 |
func StartCommand(cmd *exec.Cmd, interactive bool) (io.WriteCloser, io.ReadCloser, error) {
|
| 59 | 58 |
if interactive {
|
| 60 | 59 |
term, err := pty.Start(cmd) |
| ... | ... |
@@ -76,5 +72,3 @@ func StartCommand(cmd *exec.Cmd, interactive bool) (io.WriteCloser, io.ReadClose |
| 76 | 76 |
} |
| 77 | 77 |
return stdin, stdout, nil |
| 78 | 78 |
} |
| 79 |
- |
|
| 80 |
- |
| ... | ... |
@@ -1,129 +1,129 @@ |
| 1 | 1 |
package fs |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
- "fmt" |
|
| 5 |
- "path/filepath" |
|
| 6 |
- "os" |
|
| 7 |
- "strings" |
|
| 4 |
+ "fmt" |
|
| 5 |
+ "os" |
|
| 6 |
+ "path/filepath" |
|
| 7 |
+ "strings" |
|
| 8 | 8 |
) |
| 9 | 9 |
|
| 10 | 10 |
type ChangeType int |
| 11 | 11 |
|
| 12 | 12 |
const ( |
| 13 |
- ChangeModify = iota |
|
| 14 |
- ChangeAdd |
|
| 15 |
- ChangeDelete |
|
| 13 |
+ ChangeModify = iota |
|
| 14 |
+ ChangeAdd |
|
| 15 |
+ ChangeDelete |
|
| 16 | 16 |
) |
| 17 | 17 |
|
| 18 | 18 |
type Change struct {
|
| 19 |
- Path string |
|
| 20 |
- Kind ChangeType |
|
| 19 |
+ Path string |
|
| 20 |
+ Kind ChangeType |
|
| 21 | 21 |
} |
| 22 | 22 |
|
| 23 | 23 |
func (change *Change) String() string {
|
| 24 |
- var kind string |
|
| 25 |
- switch change.Kind {
|
|
| 26 |
- case ChangeModify: |
|
| 27 |
- kind = "C" |
|
| 28 |
- case ChangeAdd: |
|
| 29 |
- kind = "A" |
|
| 30 |
- case ChangeDelete: |
|
| 31 |
- kind = "D" |
|
| 32 |
- } |
|
| 33 |
- return fmt.Sprintf("%s %s", kind, change.Path)
|
|
| 24 |
+ var kind string |
|
| 25 |
+ switch change.Kind {
|
|
| 26 |
+ case ChangeModify: |
|
| 27 |
+ kind = "C" |
|
| 28 |
+ case ChangeAdd: |
|
| 29 |
+ kind = "A" |
|
| 30 |
+ case ChangeDelete: |
|
| 31 |
+ kind = "D" |
|
| 32 |
+ } |
|
| 33 |
+ return fmt.Sprintf("%s %s", kind, change.Path)
|
|
| 34 | 34 |
} |
| 35 | 35 |
|
| 36 | 36 |
func (store *Store) Changes(mp *Mountpoint) ([]Change, error) {
|
| 37 |
- var changes []Change |
|
| 38 |
- image, err := store.Get(mp.Image) |
|
| 39 |
- if err != nil {
|
|
| 40 |
- return nil, err |
|
| 41 |
- } |
|
| 42 |
- layers, err := image.layers() |
|
| 43 |
- if err != nil {
|
|
| 44 |
- return nil, err |
|
| 45 |
- } |
|
| 46 |
- |
|
| 47 |
- err = filepath.Walk(mp.Rw, func(path string, f os.FileInfo, err error) error {
|
|
| 48 |
- if err != nil {
|
|
| 49 |
- return err |
|
| 50 |
- } |
|
| 51 |
- |
|
| 52 |
- // Rebase path |
|
| 53 |
- path, err = filepath.Rel(mp.Rw, path) |
|
| 54 |
- if err != nil {
|
|
| 55 |
- return err |
|
| 56 |
- } |
|
| 57 |
- path = filepath.Join("/", path)
|
|
| 58 |
- |
|
| 59 |
- // Skip root |
|
| 60 |
- if path == "/" {
|
|
| 61 |
- return nil |
|
| 62 |
- } |
|
| 63 |
- |
|
| 64 |
- // Skip AUFS metadata |
|
| 65 |
- if matched, err := filepath.Match("/.wh..wh.*", path); err != nil || matched {
|
|
| 66 |
- return err |
|
| 67 |
- } |
|
| 68 |
- |
|
| 69 |
- change := Change{
|
|
| 70 |
- Path: path, |
|
| 71 |
- } |
|
| 72 |
- |
|
| 73 |
- // Find out what kind of modification happened |
|
| 74 |
- file := filepath.Base(path) |
|
| 75 |
- // If there is a whiteout, then the file was removed |
|
| 76 |
- if strings.HasPrefix(file, ".wh.") {
|
|
| 77 |
- originalFile := strings.TrimLeft(file, ".wh.") |
|
| 78 |
- change.Path = filepath.Join(filepath.Dir(path), originalFile) |
|
| 79 |
- change.Kind = ChangeDelete |
|
| 80 |
- } else {
|
|
| 81 |
- // Otherwise, the file was added |
|
| 82 |
- change.Kind = ChangeAdd |
|
| 83 |
- |
|
| 84 |
- // ...Unless it already existed in a top layer, in which case, it's a modification |
|
| 85 |
- for _, layer := range layers {
|
|
| 86 |
- stat, err := os.Stat(filepath.Join(layer, path)) |
|
| 87 |
- if err != nil && !os.IsNotExist(err) {
|
|
| 88 |
- return err |
|
| 89 |
- } |
|
| 90 |
- if err == nil {
|
|
| 91 |
- // The file existed in the top layer, so that's a modification |
|
| 92 |
- |
|
| 93 |
- // However, if it's a directory, maybe it wasn't actually modified. |
|
| 94 |
- // If you modify /foo/bar/baz, then /foo will be part of the changed files only because it's the parent of bar |
|
| 95 |
- if stat.IsDir() && f.IsDir() {
|
|
| 96 |
- if f.Size() == stat.Size() && f.Mode() == stat.Mode() && f.ModTime() == stat.ModTime() {
|
|
| 97 |
- // Both directories are the same, don't record the change |
|
| 98 |
- return nil |
|
| 99 |
- } |
|
| 100 |
- } |
|
| 101 |
- change.Kind = ChangeModify |
|
| 102 |
- break |
|
| 103 |
- } |
|
| 104 |
- } |
|
| 105 |
- } |
|
| 106 |
- |
|
| 107 |
- // Record change |
|
| 108 |
- changes = append(changes, change) |
|
| 109 |
- return nil |
|
| 110 |
- }) |
|
| 111 |
- if err != nil {
|
|
| 112 |
- return nil, err |
|
| 113 |
- } |
|
| 114 |
- return changes, nil |
|
| 37 |
+ var changes []Change |
|
| 38 |
+ image, err := store.Get(mp.Image) |
|
| 39 |
+ if err != nil {
|
|
| 40 |
+ return nil, err |
|
| 41 |
+ } |
|
| 42 |
+ layers, err := image.layers() |
|
| 43 |
+ if err != nil {
|
|
| 44 |
+ return nil, err |
|
| 45 |
+ } |
|
| 46 |
+ |
|
| 47 |
+ err = filepath.Walk(mp.Rw, func(path string, f os.FileInfo, err error) error {
|
|
| 48 |
+ if err != nil {
|
|
| 49 |
+ return err |
|
| 50 |
+ } |
|
| 51 |
+ |
|
| 52 |
+ // Rebase path |
|
| 53 |
+ path, err = filepath.Rel(mp.Rw, path) |
|
| 54 |
+ if err != nil {
|
|
| 55 |
+ return err |
|
| 56 |
+ } |
|
| 57 |
+ path = filepath.Join("/", path)
|
|
| 58 |
+ |
|
| 59 |
+ // Skip root |
|
| 60 |
+ if path == "/" {
|
|
| 61 |
+ return nil |
|
| 62 |
+ } |
|
| 63 |
+ |
|
| 64 |
+ // Skip AUFS metadata |
|
| 65 |
+ if matched, err := filepath.Match("/.wh..wh.*", path); err != nil || matched {
|
|
| 66 |
+ return err |
|
| 67 |
+ } |
|
| 68 |
+ |
|
| 69 |
+ change := Change{
|
|
| 70 |
+ Path: path, |
|
| 71 |
+ } |
|
| 72 |
+ |
|
| 73 |
+ // Find out what kind of modification happened |
|
| 74 |
+ file := filepath.Base(path) |
|
| 75 |
+ // If there is a whiteout, then the file was removed |
|
| 76 |
+ if strings.HasPrefix(file, ".wh.") {
|
|
| 77 |
+ originalFile := strings.TrimLeft(file, ".wh.") |
|
| 78 |
+ change.Path = filepath.Join(filepath.Dir(path), originalFile) |
|
| 79 |
+ change.Kind = ChangeDelete |
|
| 80 |
+ } else {
|
|
| 81 |
+ // Otherwise, the file was added |
|
| 82 |
+ change.Kind = ChangeAdd |
|
| 83 |
+ |
|
| 84 |
+ // ...Unless it already existed in a top layer, in which case, it's a modification |
|
| 85 |
+ for _, layer := range layers {
|
|
| 86 |
+ stat, err := os.Stat(filepath.Join(layer, path)) |
|
| 87 |
+ if err != nil && !os.IsNotExist(err) {
|
|
| 88 |
+ return err |
|
| 89 |
+ } |
|
| 90 |
+ if err == nil {
|
|
| 91 |
+ // The file existed in the top layer, so that's a modification |
|
| 92 |
+ |
|
| 93 |
+ // However, if it's a directory, maybe it wasn't actually modified. |
|
| 94 |
+ // If you modify /foo/bar/baz, then /foo will be part of the changed files only because it's the parent of bar |
|
| 95 |
+ if stat.IsDir() && f.IsDir() {
|
|
| 96 |
+ if f.Size() == stat.Size() && f.Mode() == stat.Mode() && f.ModTime() == stat.ModTime() {
|
|
| 97 |
+ // Both directories are the same, don't record the change |
|
| 98 |
+ return nil |
|
| 99 |
+ } |
|
| 100 |
+ } |
|
| 101 |
+ change.Kind = ChangeModify |
|
| 102 |
+ break |
|
| 103 |
+ } |
|
| 104 |
+ } |
|
| 105 |
+ } |
|
| 106 |
+ |
|
| 107 |
+ // Record change |
|
| 108 |
+ changes = append(changes, change) |
|
| 109 |
+ return nil |
|
| 110 |
+ }) |
|
| 111 |
+ if err != nil {
|
|
| 112 |
+ return nil, err |
|
| 113 |
+ } |
|
| 114 |
+ return changes, nil |
|
| 115 | 115 |
} |
| 116 | 116 |
|
| 117 | 117 |
// Reset removes all changes to the filesystem, reverting it to its initial state. |
| 118 | 118 |
func (mp *Mountpoint) Reset() error {
|
| 119 |
- if err := os.RemoveAll(mp.Rw); err != nil {
|
|
| 120 |
- return err |
|
| 121 |
- } |
|
| 122 |
- // We removed the RW directory itself along with its content: let's re-create an empty one. |
|
| 123 |
- if err := mp.createFolders(); err != nil {
|
|
| 124 |
- return err |
|
| 125 |
- } |
|
| 126 |
- return nil |
|
| 119 |
+ if err := os.RemoveAll(mp.Rw); err != nil {
|
|
| 120 |
+ return err |
|
| 121 |
+ } |
|
| 122 |
+ // We removed the RW directory itself along with its content: let's re-create an empty one. |
|
| 123 |
+ if err := mp.createFolders(); err != nil {
|
|
| 124 |
+ return err |
|
| 125 |
+ } |
|
| 126 |
+ return nil |
|
| 127 | 127 |
} |
| 128 | 128 |
|
| 129 | 129 |
// Open opens the named file for reading. |
| ... | ... |
@@ -141,4 +141,4 @@ func (mp *Mountpoint) Reset() error {
|
| 141 | 141 |
// return nil, err |
| 142 | 142 |
// } |
| 143 | 143 |
// return ioutil.ReadDir(filepath.Join(fs.RootFS, dirname)) |
| 144 |
-// } |
|
| 145 | 144 |
\ No newline at end of file |
| 145 |
+// } |
| ... | ... |
@@ -1,25 +1,25 @@ |
| 1 | 1 |
package fs |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "../future" |
|
| 4 | 5 |
"errors" |
| 5 |
- "path" |
|
| 6 |
- "path/filepath" |
|
| 6 |
+ "fmt" |
|
| 7 | 7 |
"io" |
| 8 | 8 |
"io/ioutil" |
| 9 | 9 |
"os" |
| 10 | 10 |
"os/exec" |
| 11 |
- "fmt" |
|
| 12 |
- "../future" |
|
| 11 |
+ "path" |
|
| 12 |
+ "path/filepath" |
|
| 13 | 13 |
) |
| 14 | 14 |
|
| 15 | 15 |
type LayerStore struct {
|
| 16 |
- Root string |
|
| 16 |
+ Root string |
|
| 17 | 17 |
} |
| 18 | 18 |
|
| 19 | 19 |
type Compression uint32 |
| 20 | 20 |
|
| 21 | 21 |
const ( |
| 22 |
- Uncompressed Compression = iota |
|
| 22 |
+ Uncompressed Compression = iota |
|
| 23 | 23 |
Bzip2 |
| 24 | 24 |
Gzip |
| 25 | 25 |
) |
| ... | ... |
@@ -80,10 +80,9 @@ func (store *LayerStore) Init() error {
|
| 80 | 80 |
return os.Mkdir(store.Root, 0700) |
| 81 | 81 |
} |
| 82 | 82 |
|
| 83 |
- |
|
| 84 | 83 |
func (store *LayerStore) Mktemp() (string, error) {
|
| 85 | 84 |
tmpName := future.RandomId() |
| 86 |
- tmpPath := path.Join(store.Root, "tmp-" + tmpName) |
|
| 85 |
+ tmpPath := path.Join(store.Root, "tmp-"+tmpName) |
|
| 87 | 86 |
if err := os.Mkdir(tmpPath, 0700); err != nil {
|
| 88 | 87 |
return "", err |
| 89 | 88 |
} |
| ... | ... |
@@ -94,7 +93,6 @@ func (store *LayerStore) layerPath(id string) string {
|
| 94 | 94 |
return path.Join(store.Root, id) |
| 95 | 95 |
} |
| 96 | 96 |
|
| 97 |
- |
|
| 98 | 97 |
func (store *LayerStore) AddLayer(id string, archive Archive, stderr io.Writer, compression Compression) (string, error) {
|
| 99 | 98 |
if _, err := os.Stat(store.layerPath(id)); err == nil {
|
| 100 | 99 |
return "", errors.New("Layer already exists: " + id)
|
| ... | ... |
@@ -1,14 +1,12 @@ |
| 1 | 1 |
package fs |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "github.com/dotcloud/docker/fake" |
|
| 4 | 5 |
"io/ioutil" |
| 5 |
- "testing" |
|
| 6 | 6 |
"os" |
| 7 |
- "github.com/dotcloud/docker/fake" |
|
| 7 |
+ "testing" |
|
| 8 | 8 |
) |
| 9 | 9 |
|
| 10 |
- |
|
| 11 |
- |
|
| 12 | 10 |
func TestLayersInit(t *testing.T) {
|
| 13 | 11 |
store := tempStore(t) |
| 14 | 12 |
defer os.RemoveAll(store.Root) |
| ... | ... |
@@ -54,7 +52,6 @@ func TestAddLayerDuplicate(t *testing.T) {
|
| 54 | 54 |
} |
| 55 | 55 |
} |
| 56 | 56 |
|
| 57 |
- |
|
| 58 | 57 |
/* |
| 59 | 58 |
* HELPER FUNCTIONS |
| 60 | 59 |
*/ |
| ... | ... |
@@ -10,9 +10,9 @@ import ( |
| 10 | 10 |
"io" |
| 11 | 11 |
"os" |
| 12 | 12 |
"path" |
| 13 |
+ "path/filepath" |
|
| 13 | 14 |
"syscall" |
| 14 | 15 |
"time" |
| 15 |
- "path/filepath" |
|
| 16 | 16 |
) |
| 17 | 17 |
|
| 18 | 18 |
type Store struct {
|
| ... | ... |
@@ -168,7 +168,6 @@ type Image struct {
|
| 168 | 168 |
store *Store `db:"-"` |
| 169 | 169 |
} |
| 170 | 170 |
|
| 171 |
- |
|
| 172 | 171 |
func (image *Image) Copy(pth string) (*Image, error) {
|
| 173 | 172 |
if err := image.store.orm.Insert(&Path{Path: pth, Image: image.Id}); err != nil {
|
| 174 | 173 |
return nil, err |
| ... | ... |
@@ -198,7 +197,7 @@ func (image *Image) Mountpoint(root, rw string) (*Mountpoint, error) {
|
| 198 | 198 |
|
| 199 | 199 |
func (image *Image) layers() ([]string, error) {
|
| 200 | 200 |
var list []string |
| 201 |
- var err error |
|
| 201 |
+ var err error |
|
| 202 | 202 |
currentImg := image |
| 203 | 203 |
for currentImg != nil {
|
| 204 | 204 |
if layer := image.store.layers.Get(image.Id); layer != "" {
|
| ... | ... |
@@ -1,12 +1,12 @@ |
| 1 | 1 |
package future |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "bytes" |
|
| 4 | 5 |
"crypto/sha256" |
| 5 |
- "io" |
|
| 6 | 6 |
"fmt" |
| 7 |
- "time" |
|
| 8 |
- "bytes" |
|
| 7 |
+ "io" |
|
| 9 | 8 |
"math/rand" |
| 9 |
+ "time" |
|
| 10 | 10 |
) |
| 11 | 11 |
|
| 12 | 12 |
func Seed() {
|
| ... | ... |
@@ -30,18 +30,18 @@ func HumanDuration(d time.Duration) string {
|
| 30 | 30 |
return "About a minute" |
| 31 | 31 |
} else if minutes < 60 {
|
| 32 | 32 |
return fmt.Sprintf("%d minutes", minutes)
|
| 33 |
- } else if hours := int(d.Hours()); hours == 1{
|
|
| 33 |
+ } else if hours := int(d.Hours()); hours == 1 {
|
|
| 34 | 34 |
return "About an hour" |
| 35 | 35 |
} else if hours < 48 {
|
| 36 | 36 |
return fmt.Sprintf("%d hours", hours)
|
| 37 |
- } else if hours < 24 * 7 * 2 {
|
|
| 38 |
- return fmt.Sprintf("%d days", hours / 24)
|
|
| 39 |
- } else if hours < 24 * 30 * 3 {
|
|
| 40 |
- return fmt.Sprintf("%d weeks", hours / 24 / 7)
|
|
| 41 |
- } else if hours < 24 * 365 * 2 {
|
|
| 42 |
- return fmt.Sprintf("%d months", hours / 24 / 30)
|
|
| 37 |
+ } else if hours < 24*7*2 {
|
|
| 38 |
+ return fmt.Sprintf("%d days", hours/24)
|
|
| 39 |
+ } else if hours < 24*30*3 {
|
|
| 40 |
+ return fmt.Sprintf("%d weeks", hours/24/7)
|
|
| 41 |
+ } else if hours < 24*365*2 {
|
|
| 42 |
+ return fmt.Sprintf("%d months", hours/24/30)
|
|
| 43 | 43 |
} |
| 44 |
- return fmt.Sprintf("%d years", d.Hours() / 24 / 365)
|
|
| 44 |
+ return fmt.Sprintf("%d years", d.Hours()/24/365)
|
|
| 45 | 45 |
} |
| 46 | 46 |
|
| 47 | 47 |
func randomBytes() io.Reader {
|
| ... | ... |
@@ -60,4 +60,3 @@ func Go(f func() error) chan error {
|
| 60 | 60 |
}() |
| 61 | 61 |
return ch |
| 62 | 62 |
} |
| 63 |
- |
| ... | ... |
@@ -1,27 +1,25 @@ |
| 1 | 1 |
package image |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "encoding/json" |
|
| 5 |
+ "errors" |
|
| 6 |
+ "github.com/dotcloud/docker/future" |
|
| 4 | 7 |
"io" |
| 5 | 8 |
"io/ioutil" |
| 6 |
- "encoding/json" |
|
| 7 |
- "time" |
|
| 9 |
+ "os" |
|
| 8 | 10 |
"path" |
| 9 | 11 |
"path/filepath" |
| 10 |
- "errors" |
|
| 11 | 12 |
"sort" |
| 12 |
- "os" |
|
| 13 |
- "github.com/dotcloud/docker/future" |
|
| 14 | 13 |
"strings" |
| 14 |
+ "time" |
|
| 15 | 15 |
) |
| 16 | 16 |
|
| 17 |
- |
|
| 18 | 17 |
type Store struct {
|
| 19 | 18 |
*Index |
| 20 |
- Root string |
|
| 21 |
- Layers *LayerStore |
|
| 19 |
+ Root string |
|
| 20 |
+ Layers *LayerStore |
|
| 22 | 21 |
} |
| 23 | 22 |
|
| 24 |
- |
|
| 25 | 23 |
func New(root string) (*Store, error) {
|
| 26 | 24 |
abspath, err := filepath.Abs(root) |
| 27 | 25 |
if err != nil {
|
| ... | ... |
@@ -38,8 +36,8 @@ func New(root string) (*Store, error) {
|
| 38 | 38 |
return nil, err |
| 39 | 39 |
} |
| 40 | 40 |
return &Store{
|
| 41 |
- Root: abspath, |
|
| 42 |
- Index: NewIndex(path.Join(root, "index.json")), |
|
| 41 |
+ Root: abspath, |
|
| 42 |
+ Index: NewIndex(path.Join(root, "index.json")), |
|
| 43 | 43 |
Layers: layers, |
| 44 | 44 |
}, nil |
| 45 | 45 |
} |
| ... | ... |
@@ -47,7 +45,7 @@ func New(root string) (*Store, error) {
|
| 47 | 47 |
type Compression uint32 |
| 48 | 48 |
|
| 49 | 49 |
const ( |
| 50 |
- Uncompressed Compression = iota |
|
| 50 |
+ Uncompressed Compression = iota |
|
| 51 | 51 |
Bzip2 |
| 52 | 52 |
Gzip |
| 53 | 53 |
) |
| ... | ... |
@@ -79,20 +77,19 @@ func (store *Store) Create(name string, source string, layers ...string) (*Image |
| 79 | 79 |
return image, nil |
| 80 | 80 |
} |
| 81 | 81 |
|
| 82 |
- |
|
| 83 | 82 |
// Index |
| 84 | 83 |
|
| 85 | 84 |
type Index struct {
|
| 86 |
- Path string |
|
| 87 |
- ByName map[string]*History |
|
| 88 |
- ById map[string]*Image |
|
| 85 |
+ Path string |
|
| 86 |
+ ByName map[string]*History |
|
| 87 |
+ ById map[string]*Image |
|
| 89 | 88 |
} |
| 90 | 89 |
|
| 91 | 90 |
func NewIndex(path string) *Index {
|
| 92 | 91 |
return &Index{
|
| 93 |
- Path: path, |
|
| 92 |
+ Path: path, |
|
| 94 | 93 |
ByName: make(map[string]*History), |
| 95 |
- ById: make(map[string]*Image), |
|
| 94 |
+ ById: make(map[string]*Image), |
|
| 96 | 95 |
} |
| 97 | 96 |
} |
| 98 | 97 |
|
| ... | ... |
@@ -222,7 +219,7 @@ func (index *Index) Names() []string {
|
| 222 | 222 |
if err := index.load(); err != nil {
|
| 223 | 223 |
return []string{}
|
| 224 | 224 |
} |
| 225 |
- var names[]string |
|
| 225 |
+ var names []string |
|
| 226 | 226 |
for name := range index.ByName {
|
| 227 | 227 |
names = append(names, name) |
| 228 | 228 |
} |
| ... | ... |
@@ -285,23 +282,23 @@ func (history *History) Add(image *Image) {
|
| 285 | 285 |
func (history *History) Del(id string) {
|
| 286 | 286 |
for idx, image := range *history {
|
| 287 | 287 |
if image.Id == id {
|
| 288 |
- *history = append((*history)[:idx], (*history)[idx + 1:]...) |
|
| 288 |
+ *history = append((*history)[:idx], (*history)[idx+1:]...) |
|
| 289 | 289 |
} |
| 290 | 290 |
} |
| 291 | 291 |
} |
| 292 | 292 |
|
| 293 | 293 |
type Image struct {
|
| 294 |
- Id string // Globally unique identifier |
|
| 295 |
- Layers []string // Absolute paths |
|
| 296 |
- Created time.Time |
|
| 297 |
- Parent string |
|
| 294 |
+ Id string // Globally unique identifier |
|
| 295 |
+ Layers []string // Absolute paths |
|
| 296 |
+ Created time.Time |
|
| 297 |
+ Parent string |
|
| 298 | 298 |
} |
| 299 | 299 |
|
| 300 | 300 |
func (image *Image) IdParts() (string, string) {
|
| 301 | 301 |
if len(image.Id) < 8 {
|
| 302 | 302 |
return "", image.Id |
| 303 | 303 |
} |
| 304 |
- hash := image.Id[len(image.Id)-8:len(image.Id)] |
|
| 304 |
+ hash := image.Id[len(image.Id)-8 : len(image.Id)] |
|
| 305 | 305 |
name := image.Id[:len(image.Id)-9] |
| 306 | 306 |
return name, hash |
| 307 | 307 |
} |
| ... | ... |
@@ -322,7 +319,7 @@ func generateImageId(name string, layers []string) (string, error) {
|
| 322 | 322 |
for _, layer := range layers {
|
| 323 | 323 |
ids += path.Base(layer) |
| 324 | 324 |
} |
| 325 |
- if h, err := future.ComputeId(strings.NewReader(ids)); err != nil {
|
|
| 325 |
+ if h, err := future.ComputeId(strings.NewReader(ids)); err != nil {
|
|
| 326 | 326 |
return "", err |
| 327 | 327 |
} else {
|
| 328 | 328 |
hash = h |
| ... | ... |
@@ -337,9 +334,9 @@ func NewImage(name string, layers []string, parent string) (*Image, error) {
|
| 337 | 337 |
return nil, err |
| 338 | 338 |
} |
| 339 | 339 |
return &Image{
|
| 340 |
- Id: id, |
|
| 341 |
- Layers: layers, |
|
| 342 |
- Created: time.Now(), |
|
| 343 |
- Parent: parent, |
|
| 340 |
+ Id: id, |
|
| 341 |
+ Layers: layers, |
|
| 342 |
+ Created: time.Now(), |
|
| 343 |
+ Parent: parent, |
|
| 344 | 344 |
}, nil |
| 345 | 345 |
} |
| ... | ... |
@@ -1,13 +1,12 @@ |
| 1 | 1 |
package rcli |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "fmt" |
|
| 4 | 5 |
"net/http" |
| 5 | 6 |
"net/url" |
| 6 | 7 |
"path" |
| 7 |
- "fmt" |
|
| 8 | 8 |
) |
| 9 | 9 |
|
| 10 |
- |
|
| 11 | 10 |
// Use this key to encode an RPC call into an URL, |
| 12 | 11 |
// eg. domain.tld/path/to/method?q=get_user&q=gordon |
| 13 | 12 |
const ARG_URL_KEY = "q" |
| ... | ... |
@@ -16,18 +15,16 @@ func URLToCall(u *url.URL) (method string, args []string) {
|
| 16 | 16 |
return path.Base(u.Path), u.Query()[ARG_URL_KEY] |
| 17 | 17 |
} |
| 18 | 18 |
|
| 19 |
- |
|
| 20 | 19 |
func ListenAndServeHTTP(addr string, service Service) error {
|
| 21 | 20 |
return http.ListenAndServe(addr, http.HandlerFunc( |
| 22 |
- func (w http.ResponseWriter, r *http.Request) {
|
|
| 21 |
+ func(w http.ResponseWriter, r *http.Request) {
|
|
| 23 | 22 |
cmd, args := URLToCall(r.URL) |
| 24 | 23 |
if err := call(service, r.Body, &AutoFlush{w}, append([]string{cmd}, args...)...); err != nil {
|
| 25 |
- fmt.Fprintf(w, "Error: " + err.Error() + "\n") |
|
| 24 |
+ fmt.Fprintf(w, "Error: "+err.Error()+"\n") |
|
| 26 | 25 |
} |
| 27 | 26 |
})) |
| 28 | 27 |
} |
| 29 | 28 |
|
| 30 |
- |
|
| 31 | 29 |
type AutoFlush struct {
|
| 32 | 30 |
http.ResponseWriter |
| 33 | 31 |
} |
| ... | ... |
@@ -1,13 +1,13 @@ |
| 1 | 1 |
package rcli |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "bufio" |
|
| 5 |
+ "encoding/json" |
|
| 6 |
+ "fmt" |
|
| 4 | 7 |
"io" |
| 5 | 8 |
"io/ioutil" |
| 6 |
- "net" |
|
| 7 | 9 |
"log" |
| 8 |
- "fmt" |
|
| 9 |
- "encoding/json" |
|
| 10 |
- "bufio" |
|
| 10 |
+ "net" |
|
| 11 | 11 |
) |
| 12 | 12 |
|
| 13 | 13 |
// Connect to a remote endpoint using protocol `proto` and address `addr`, |
| ... | ... |
@@ -44,7 +44,7 @@ func ListenAndServe(proto, addr string, service Service) error {
|
| 44 | 44 |
go func() {
|
| 45 | 45 |
if err := Serve(conn, service); err != nil {
|
| 46 | 46 |
log.Printf("Error: " + err.Error() + "\n")
|
| 47 |
- fmt.Fprintf(conn, "Error: " + err.Error() + "\n") |
|
| 47 |
+ fmt.Fprintf(conn, "Error: "+err.Error()+"\n") |
|
| 48 | 48 |
} |
| 49 | 49 |
conn.Close() |
| 50 | 50 |
}() |
| ... | ... |
@@ -53,7 +53,6 @@ func ListenAndServe(proto, addr string, service Service) error {
|
| 53 | 53 |
return nil |
| 54 | 54 |
} |
| 55 | 55 |
|
| 56 |
- |
|
| 57 | 56 |
// Parse an rcli call on a new connection, and pass it to `service` if it |
| 58 | 57 |
// is valid. |
| 59 | 58 |
func Serve(conn io.ReadWriter, service Service) error {
|
| ... | ... |
@@ -68,4 +67,3 @@ func Serve(conn io.ReadWriter, service Service) error {
|
| 68 | 68 |
} |
| 69 | 69 |
return nil |
| 70 | 70 |
} |
| 71 |
- |
| ... | ... |
@@ -8,13 +8,13 @@ package rcli |
| 8 | 8 |
// are the usual suspects. |
| 9 | 9 |
|
| 10 | 10 |
import ( |
| 11 |
+ "errors" |
|
| 12 |
+ "flag" |
|
| 11 | 13 |
"fmt" |
| 12 | 14 |
"io" |
| 13 |
- "reflect" |
|
| 14 |
- "flag" |
|
| 15 | 15 |
"log" |
| 16 |
+ "reflect" |
|
| 16 | 17 |
"strings" |
| 17 |
- "errors" |
|
| 18 | 18 |
) |
| 19 | 19 |
|
| 20 | 20 |
type Service interface {
|
| ... | ... |
@@ -25,7 +25,6 @@ type Service interface {
|
| 25 | 25 |
type Cmd func(io.ReadCloser, io.Writer, ...string) error |
| 26 | 26 |
type CmdMethod func(Service, io.ReadCloser, io.Writer, ...string) error |
| 27 | 27 |
|
| 28 |
- |
|
| 29 | 28 |
func call(service Service, stdin io.ReadCloser, stdout io.Writer, args ...string) error {
|
| 30 | 29 |
if len(args) == 0 {
|
| 31 | 30 |
args = []string{"help"}
|
| ... | ... |
@@ -63,7 +62,7 @@ func getMethod(service Service, name string) Cmd {
|
| 63 | 63 |
return nil |
| 64 | 64 |
} |
| 65 | 65 |
} |
| 66 |
- methodName := "Cmd"+strings.ToUpper(name[:1])+strings.ToLower(name[1:]) |
|
| 66 |
+ methodName := "Cmd" + strings.ToUpper(name[:1]) + strings.ToLower(name[1:]) |
|
| 67 | 67 |
method, exists := reflect.TypeOf(service).MethodByName(methodName) |
| 68 | 68 |
if !exists {
|
| 69 | 69 |
return nil |
| ... | ... |
@@ -91,4 +90,3 @@ func Subcmd(output io.Writer, name, signature, description string) *flag.FlagSet |
| 91 | 91 |
} |
| 92 | 92 |
return flags |
| 93 | 93 |
} |
| 94 |
- |
| ... | ... |
@@ -1,15 +1,15 @@ |
| 1 | 1 |
package server |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ ".." |
|
| 5 |
+ "../fs" |
|
| 6 |
+ "../future" |
|
| 7 |
+ "../rcli" |
|
| 4 | 8 |
"bufio" |
| 5 | 9 |
"bytes" |
| 6 | 10 |
"encoding/json" |
| 7 | 11 |
"errors" |
| 8 | 12 |
"fmt" |
| 9 |
- ".." |
|
| 10 |
- "../future" |
|
| 11 |
- "../fs" |
|
| 12 |
- "../rcli" |
|
| 13 | 13 |
"io" |
| 14 | 14 |
"net/http" |
| 15 | 15 |
"net/url" |
| ... | ... |
@@ -269,8 +269,8 @@ func (srv *Server) CmdInspect(stdin io.ReadCloser, stdout io.Writer, args ...str |
| 269 | 269 |
var obj interface{}
|
| 270 | 270 |
if container := srv.containers.Get(name); container != nil {
|
| 271 | 271 |
obj = container |
| 272 |
- //} else if image, err := srv.images.List(name); image != nil {
|
|
| 273 |
- // obj = image |
|
| 272 |
+ //} else if image, err := srv.images.List(name); image != nil {
|
|
| 273 |
+ // obj = image |
|
| 274 | 274 |
} else {
|
| 275 | 275 |
return errors.New("No such container or image: " + name)
|
| 276 | 276 |
} |