If .dockerignore mentions either then the client will send them to the daemon but the daemon will erase them after the Dockerfile has been parsed to simulate them never being sent in the first place. an events test kept failing for me so I tried to fix that too Closes #8330 Signed-off-by: Doug Davis <dug@us.ibm.com> Upstream-commit: 6d801a3caa54ad7ef574bc426aa1ffc412c5af82 Component: engine
180 lines
3.3 KiB
Go
180 lines
3.3 KiB
Go
package volumes
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"sync"
|
|
|
|
"github.com/docker/docker/pkg/archive"
|
|
"github.com/docker/docker/pkg/symlink"
|
|
)
|
|
|
|
type Volume struct {
|
|
ID string
|
|
Path string
|
|
IsBindMount bool
|
|
Writable bool
|
|
containers map[string]struct{}
|
|
configPath string
|
|
repository *Repository
|
|
lock sync.Mutex
|
|
}
|
|
|
|
func (v *Volume) Export(resource, name string) (io.ReadCloser, error) {
|
|
if v.IsBindMount && filepath.Base(resource) == name {
|
|
name = ""
|
|
}
|
|
|
|
basePath, err := v.getResourcePath(resource)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
stat, err := os.Stat(basePath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var filter []string
|
|
if !stat.IsDir() {
|
|
d, f := path.Split(basePath)
|
|
basePath = d
|
|
filter = []string{f}
|
|
} else {
|
|
filter = []string{path.Base(basePath)}
|
|
basePath = path.Dir(basePath)
|
|
}
|
|
return archive.TarWithOptions(basePath, &archive.TarOptions{
|
|
Compression: archive.Uncompressed,
|
|
Name: name,
|
|
IncludeFiles: filter,
|
|
})
|
|
}
|
|
|
|
func (v *Volume) IsDir() (bool, error) {
|
|
stat, err := os.Stat(v.Path)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
return stat.IsDir(), nil
|
|
}
|
|
|
|
func (v *Volume) Containers() []string {
|
|
v.lock.Lock()
|
|
|
|
var containers []string
|
|
for c := range v.containers {
|
|
containers = append(containers, c)
|
|
}
|
|
|
|
v.lock.Unlock()
|
|
return containers
|
|
}
|
|
|
|
func (v *Volume) RemoveContainer(containerId string) {
|
|
v.lock.Lock()
|
|
delete(v.containers, containerId)
|
|
v.lock.Unlock()
|
|
}
|
|
|
|
func (v *Volume) AddContainer(containerId string) {
|
|
v.lock.Lock()
|
|
v.containers[containerId] = struct{}{}
|
|
v.lock.Unlock()
|
|
}
|
|
|
|
func (v *Volume) createIfNotExist() error {
|
|
if stat, err := os.Stat(v.Path); err != nil && os.IsNotExist(err) {
|
|
if stat.IsDir() {
|
|
os.MkdirAll(v.Path, 0755)
|
|
}
|
|
|
|
if err := os.MkdirAll(filepath.Dir(v.Path), 0755); err != nil {
|
|
return err
|
|
}
|
|
f, err := os.OpenFile(v.Path, os.O_CREATE, 0755)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
f.Close()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (v *Volume) initialize() error {
|
|
v.lock.Lock()
|
|
defer v.lock.Unlock()
|
|
|
|
if err := v.createIfNotExist(); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := os.MkdirAll(v.configPath, 0755); err != nil {
|
|
return err
|
|
}
|
|
jsonPath, err := v.jsonPath()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
f, err := os.Create(jsonPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
return v.toDisk()
|
|
}
|
|
|
|
func (v *Volume) ToDisk() error {
|
|
v.lock.Lock()
|
|
defer v.lock.Unlock()
|
|
return v.toDisk()
|
|
}
|
|
func (v *Volume) toDisk() error {
|
|
data, err := json.Marshal(v)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
pth, err := v.jsonPath()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return ioutil.WriteFile(pth, data, 0666)
|
|
}
|
|
func (v *Volume) FromDisk() error {
|
|
v.lock.Lock()
|
|
defer v.lock.Unlock()
|
|
pth, err := v.jsonPath()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
jsonSource, err := os.Open(pth)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer jsonSource.Close()
|
|
|
|
dec := json.NewDecoder(jsonSource)
|
|
|
|
return dec.Decode(v)
|
|
}
|
|
|
|
func (v *Volume) jsonPath() (string, error) {
|
|
return v.getRootResourcePath("config.json")
|
|
}
|
|
func (v *Volume) getRootResourcePath(path string) (string, error) {
|
|
cleanPath := filepath.Join("/", path)
|
|
return symlink.FollowSymlinkInScope(filepath.Join(v.configPath, cleanPath), v.configPath)
|
|
}
|
|
|
|
func (v *Volume) getResourcePath(path string) (string, error) {
|
|
cleanPath := filepath.Join("/", path)
|
|
return symlink.FollowSymlinkInScope(filepath.Join(v.Path, cleanPath), v.Path)
|
|
}
|