@@ -14,7 +14,6 @@ import (
14
14
"net"
15
15
"net/url"
16
16
"os"
17
- "path/filepath"
18
17
"regexp"
19
18
"strings"
20
19
"sync"
@@ -602,92 +601,87 @@ func (c *DockerContainer) CopyFileFromContainer(ctx context.Context, filePath st
602
601
return ret , nil
603
602
}
604
603
605
- // CopyDirToContainer copies the contents of a directory to a parent path in the container. This parent path must exist in the container first
606
- // as we cannot create it
607
- func (c * DockerContainer ) CopyDirToContainer (ctx context.Context , hostDirPath string , containerParentPath string , fileMode int64 ) error {
608
- dir , err := isDir (hostDirPath )
609
- if err != nil {
604
+ // CopyDirToContainer copies the contents of hostPath to containerPath in the container.
605
+ // If fileMode is non-zero all files will have their file permissions set to that of fileMode
606
+ // otherwise the file permissions will be copied from the host.
607
+ // If fileMode contains bits not part of [fs.ModePerm] | [fs.ModeSetuid] | [fs.ModeSetgid] |
608
+ // [fs.ModeSticky] an error is returned.
609
+ // If the parent of the containerPath does not exist an error is returned.
610
+ //
611
+ // Deprecated: use [DockerContainer.CopyHostPathTo] instead.
612
+ func (c * DockerContainer ) CopyDirToContainer (ctx context.Context , hostPath string , containerPath string , fileMode int64 ) error {
613
+ if err := validateFileMode (fileMode ); err != nil {
610
614
return err
611
615
}
612
616
613
- if ! dir {
614
- // it's not a dir: let the consumer to handle an error
615
- return fmt .Errorf ("path %s is not a directory" , hostDirPath )
616
- }
617
-
618
- buff , err := tarDir (hostDirPath , fileMode )
617
+ dir , err := isDir (hostPath )
619
618
if err != nil {
620
619
return err
621
620
}
622
621
623
- // create the directory under its parent
624
- parent := filepath .Dir (containerParentPath )
625
-
626
- err = c .provider .client .CopyToContainer (ctx , c .ID , parent , buff , container.CopyToContainerOptions {})
627
- if err != nil {
628
- return err
622
+ if ! dir {
623
+ // It's not a dir: let the consumer to handle an error.
624
+ return fmt .Errorf ("host dir path %q is not a directory" , hostPath )
629
625
}
630
- defer c .provider .Close ()
631
626
632
- return nil
627
+ return c . CopyHostPathTo ( ctx , hostPath , containerPath , copyToFileMode ( fileMode ))
633
628
}
634
629
635
- func (c * DockerContainer ) CopyFileToContainer (ctx context.Context , hostFilePath string , containerFilePath string , fileMode int64 ) error {
636
- dir , err := isDir (hostFilePath )
630
+ // CopyFileToContainer copies hostPath to containerPath in the container.
631
+ // If fileMode is non-zero the files permissions will be set to that of fileMode
632
+ // otherwise the file permissions will be set to that of the file in hostPath.
633
+ // If fileMode contains bits not part of [fs.ModePerm] | [fs.ModeSetuid] | [fs.ModeSetgid] |
634
+ // [fs.ModeSticky] an error is returned.
635
+ // If the parent of the containerPath does not exist an error is returned.
636
+ // If hostPath is a directory this is equivalent to [DockerContainer.CopyDirToContainer].
637
+ //
638
+ // Deprecated: use [DockerContainer.CopyHostPathTo] instead.
639
+ func (c * DockerContainer ) CopyFileToContainer (ctx context.Context , hostPath string , containerPath string , fileMode int64 ) error {
640
+ dir , err := isDir (hostPath )
637
641
if err != nil {
638
642
return err
639
643
}
640
644
641
645
if dir {
642
- return c .CopyDirToContainer (ctx , hostFilePath , containerFilePath , fileMode )
643
- }
644
-
645
- f , err := os .Open (hostFilePath )
646
- if err != nil {
647
- return err
646
+ return c .CopyDirToContainer (ctx , hostPath , containerPath , fileMode )
648
647
}
649
- defer f .Close ()
650
648
651
- info , err := f . Stat ( )
649
+ data , err := os . ReadFile ( hostPath )
652
650
if err != nil {
653
- return err
651
+ return fmt . Errorf ( "read file: %w" , err )
654
652
}
655
653
656
- // In Go 1.22 os.File is always an io.WriterTo. However, testcontainers
657
- // currently allows Go 1.21, so we need to trick the compiler a little.
658
- var file fs.File = f
659
- return c .copyToContainer (ctx , func (tw io.Writer ) error {
660
- // Attempt optimized writeTo, implemented in linux
661
- if wt , ok := file .(io.WriterTo ); ok {
662
- _ , err := wt .WriteTo (tw )
663
- return err
654
+ if fileMode == 0 {
655
+ fi , err := os .Stat (hostPath )
656
+ if err != nil {
657
+ return fmt .Errorf ("stat file: %w" , err )
664
658
}
665
- _ , err := io .Copy (tw , f )
666
- return err
667
- }, info .Size (), containerFilePath , fileMode )
668
- }
669
659
670
- // CopyToContainer copies fileContent data to a file in container
671
- func (c * DockerContainer ) CopyToContainer (ctx context.Context , fileContent []byte , containerFilePath string , fileMode int64 ) error {
672
- return c .copyToContainer (ctx , func (tw io.Writer ) error {
673
- _ , err := tw .Write (fileContent )
674
- return err
675
- }, int64 (len (fileContent )), containerFilePath , fileMode )
660
+ fileMode = int64 (fi .Mode ())
661
+ }
662
+
663
+ return c .CopyToContainer (ctx , data , containerPath , fileMode )
676
664
}
677
665
678
- func (c * DockerContainer ) copyToContainer (ctx context.Context , fileContent func (tw io.Writer ) error , fileContentSize int64 , containerFilePath string , fileMode int64 ) error {
679
- buffer , err := tarFile (containerFilePath , fileContent , fileContentSize , fileMode )
680
- if err != nil {
666
+ // CopyToContainer copies a file with contents of fileContent to containerPath in the
667
+ // container with the given fileMode.
668
+ // If fileMode contains bits not part of [fs.ModePerm] | [fs.ModeSetuid] | [fs.ModeSetgid] |
669
+ // [fs.ModeSticky] an error is returned.
670
+ func (c * DockerContainer ) CopyToContainer (ctx context.Context , fileContent []byte , containerPath string , fileMode int64 ) error {
671
+ if err := validateFileMode (fileMode ); err != nil {
681
672
return err
682
673
}
683
674
684
- err = c .provider .client .CopyToContainer (ctx , c .ID , "/" , buffer , container.CopyToContainerOptions {})
675
+ // Create a tar with the single file containing the a file with the
676
+ // fully qualified container path as the name.
677
+ tar , err := tarFile (containerPath , fileContent , fs .FileMode (fileMode ))
685
678
if err != nil {
686
679
return err
687
680
}
688
- defer c .provider .Close ()
689
681
690
- return nil
682
+ // As the name of the file in the tar is the fully qualified container path
683
+ // it should by extracted in the container's root directory.
684
+ return c .copyTarTo (ctx , tar , "/" )
691
685
}
692
686
693
687
type LogProductionOption func (* DockerContainer )
0 commit comments