Passed
Push — master ( 26e86a...9b47e1 )
by Tom
03:10
created

TarCopier::extCopyDirectory()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 6
c 1
b 0
f 0
nc 2
nop 4
dl 0
loc 11
ccs 7
cts 7
cp 1
crap 2
rs 10
1
<?php
2
3
/* this file is part of pipelines */
4
5
namespace Ktomk\Pipelines\Runner\Docker\Provision;
6
7
use Ktomk\Pipelines\Cli\Exec;
8
use Ktomk\Pipelines\Lib;
9
use Ktomk\Pipelines\LibFs;
10
use Ktomk\Pipelines\LibTmp;
11
use Ktomk\Pipelines\Value\SideEffect\DestructibleString;
12
13
/**
14
 * Copy files and directories (into a running container)
15
 *
16
 * This basically works with tar and docker cp as we found it working
17
 * from very early iterations, therefore the "Tar" class name prefix.
18
 *
19
 * Straight extraction from StepRunner for static methods
20
 */
21
class TarCopier
22
{
23
    /**
24
     * Make an empty directory with user/group from an existing directory (on
25
     * the system pipelines is running, the source directory).
26
     *
27
     * This ensures the target directory pathname exists within the container
28
     * on return status 0.
29
     *
30
     * If the target pathname is '/', the operation is always successful even
31
     * no operation is done. reason is that '/' is expected to be already setup.
32
     *
33
     * If the target path is empty or relative, the behaviour is undefined.
34
     *
35
     * @param Exec $exec
36
     * @param string $id container id
37
     * @param string $source directory to obtain file-properties from (user, group)
38
     * @param string $target directory to create within container with those properties
39
     *
40
     * @return int status
41
     */
42 4
    public static function extMakeEmptyDirectory(Exec $exec, $id, $source, $target)
43
    {
44 4
        if ('/' === $target) {
45 1
            return 0;
46
        }
47
48 3
        if ('' === $source) {
49 1
            throw new \InvalidArgumentException('empty source');
50
        }
51
52 2
        if (!is_dir($source)) {
53 1
            throw new \InvalidArgumentException("not a directory: '${source}'");
54
        }
55
56 1
        $tmpDir = DestructibleString::rmDir(LibTmp::tmpDir('pipelines-cp.'));
57 1
        LibFs::symlinkWithParents($source, $tmpDir . $target);
58
59 1
        $cd = Lib::cmd('cd', array($tmpDir . '/.'));
60 1
        $tar = Lib::cmd('tar', array('c', '-h', '-f', '-', '--no-recursion', '.' . $target));
61 1
        $dockerCp = Lib::cmd('docker ', array('cp', '-', $id . ':/.'));
62
63 1
        return $exec->pass("${cd} && ${tar} | ${dockerCp}", array());
64
    }
65
66
    /**
67
     * Make a (recursive) directory copy from an existing directory (on
68
     * the system pipelines is running, the source directory) into the
69
     * containers target directory.
70
     *
71
     * The behaviour whether the target directory exists within the container
72
     * or not depends on the underlying docker cp command. When writing this
73
     * method assumption is it needs to, {@see TarCopier::extMakeEmptyDirectory()}.
74
     *
75
     * If the target path is empty or relative, the behaviour is undefined.
76
     *
77
     * @param Exec $exec
78
     * @param string $id container id
79
     * @param string $source directory
80
     * @param string $target directory to create within container
81
     *
82
     * @return int status
83
     */
84 2
    public static function extCopyDirectory(Exec $exec, $id, $source, $target)
85
    {
86 2
        if ('' === $source) {
87 1
            throw new \InvalidArgumentException('empty source');
88
        }
89
90 1
        $cd = Lib::cmd('cd', array($source . '/.'));
91 1
        $tar = Lib::cmd('tar', array('c', '-f', '-', '.'));
92 1
        $dockerCp = Lib::cmd('docker ', array('cp', '-', $id . ':' . $target));
93
94 1
        return $exec->pass("${cd} && ${tar} | ${dockerCp}", array());
95
    }
96
97
    /**
98
     * Make a (recursive) directory copy from an existing directory (on
99
     * the system pipelines is running, the source directory) into the
100
     * containers target directory.
101
     *
102
     * The target directory is created in the container with the user/group
103
     * info from source.
104
     *
105
     * @param Exec $exec
106
     * @param string $id container id
107
     * @param string $source directory
108
     * @param string $target directory to create within container
109
     *
110
     * @return int
111
     */
112 1
    public static function extDeployDirectory(Exec $exec, $id, $source, $target)
113
    {
114 1
        $status = self::extMakeEmptyDirectory($exec, $id, $source, $target);
115 1
        if (0 !== $status) {
116 1
            return $status;
117
        }
118
119 1
        return self::extCopyDirectory($exec, $id, $source, $target);
120
    }
121
}
122