keepClient IKeepClient
hostOutputDir string
ctrOutputDir string
+ binds []string
mounts map[string]arvados.Mount
secretMounts map[string]arvados.Mount
logger printfer
func (cp *copier) Copy() (string, error) {
err := cp.walkMount("", cp.ctrOutputDir, limitFollowSymlinks, true)
if err != nil {
- return "", err
+ return "", fmt.Errorf("error scanning files to copy to output: %v", err)
}
fs, err := (&arvados.Collection{ManifestText: cp.manifest}).FileSystem(cp.client, cp.keepClient)
if err != nil {
- return "", err
+ return "", fmt.Errorf("error creating Collection.FileSystem: %v", err)
}
for _, d := range cp.dirs {
err = fs.Mkdir(d, 0777)
- if err != nil {
- return "", err
+ if err != nil && err != os.ErrExist {
+ return "", fmt.Errorf("error making directory %q in output collection: %v", d, err)
}
}
for _, f := range cp.files {
err = cp.copyFile(fs, f)
if err != nil {
- return "", err
+ return "", fmt.Errorf("error copying file %q into output collection: %v", f, err)
}
}
return fs.MarshalManifest(".")
return err
}
cp.manifest += mft.Extract(srcRelPath, dest).Text
- case srcRoot == cp.ctrOutputDir:
- f, err := os.Open(filepath.Join(cp.hostOutputDir, ".arvados#collection"))
+ default:
+ hostRoot, err := cp.hostRoot(srcRoot)
+ if err != nil {
+ return err
+ }
+ f, err := os.Open(filepath.Join(hostRoot, ".arvados#collection"))
if err != nil {
return err
}
}
mft := manifest.Manifest{Text: coll.ManifestText}
cp.manifest += mft.Extract(srcRelPath, dest).Text
- default:
- return fmt.Errorf("cannot output %q as %q: writable collection mounted at %q", src, dest, srcRoot)
}
if walkMountsBelow {
return cp.walkMountsBelow(dest, src)
if !strings.HasPrefix(mnt, src+"/") {
continue
}
- if mntinfo.Kind == "text" || mntinfo.Kind == "json" {
+ if cp.copyRegularFiles(mntinfo) {
// These got copied into the nearest parent
// mount as regular files during setup, so
// they get copied as regular files when we
if _, isSecret := cp.secretMounts[src]; isSecret {
continue
}
- if mntinfo, isMount := cp.mounts[src]; isMount && mntinfo.Kind != "text" && mntinfo.Kind != "json" {
+ if mntinfo, isMount := cp.mounts[src]; isMount && !cp.copyRegularFiles(mntinfo) {
// If a regular file/dir somehow
// exists at a path that's also a
// mount target, ignore the file --
// the mount has already been included
// with walkMountsBelow().
//
- // (...except json/text mounts, which
- // are handled as regular files.)
+ // (...except mount types that are
+ // handled as regular files.)
continue
}
err = cp.walkHostFS(dest, src, maxSymlinks, false)
return fmt.Errorf("Unsupported file type (mode %o) in output dir: %q", fi.Mode(), src)
}
+// Return the host path that was mounted at the given path in the
+// container.
+func (cp *copier) hostRoot(ctrRoot string) (string, error) {
+ if ctrRoot == cp.ctrOutputDir {
+ return cp.hostOutputDir, nil
+ }
+ for _, bind := range cp.binds {
+ tokens := strings.Split(bind, ":")
+ if len(tokens) >= 2 && tokens[1] == ctrRoot {
+ return tokens[0], nil
+ }
+ }
+ return "", fmt.Errorf("not bind-mounted: %q", ctrRoot)
+}
+
+func (cp *copier) copyRegularFiles(m arvados.Mount) bool {
+ return m.Kind == "text" || m.Kind == "json" || (m.Kind == "collection" && m.Writable)
+}
+
func (cp *copier) getManifest(pdh string) (*manifest.Manifest, error) {
if mft, ok := cp.manifestCache[pdh]; ok {
return mft, nil