Passed
Push — master ( cef286...5c5891 )
by Andreas
11:44
created

midcom_services_rcs_backend_git::get_revision()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 1
dl 0
loc 6
ccs 0
cts 5
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @package midcom.services.rcs
4
 * @author CONTENT CONTROL https://contentcontrol.berlin
5
 * @copyright CONTENT CONTROL https://contentcontrol.berlin
6
 */
7
8
/**
9
 * @package midcom.services.rcs
10
 */
11
class midcom_services_rcs_backend_git extends midcom_services_rcs_backend
12
{
13
    /**
14
     * Save a new revision
15
     */
16 1
    public function update(string $user_id, string $updatemessage = '')
17
    {
18 1
        $author = $user_id . ' <' . $user_id . '@' . $_SERVER['REMOTE_ADDR'] . '>';
19 1
        $command = 'commit -q --allow-empty --allow-empty-message -m ' . escapeshellarg($updatemessage) .
20 1
            ' --author ' . escapeshellarg($author);
21
22 1
        $filename = $this->generate_filename();
23 1
        $relative_path = $this->relative_path($filename);
24
        // avoid the separate add cmd where possible to mitigate concurrency issues
25 1
        if (!file_exists($filename)) {
26 1
            $this->write_object($filename);
27 1
            $this->exec('add ' . $relative_path);
28
        } else {
29
            $this->write_object($filename);
30
            $command .= ' ' . $relative_path;
31
        }
32
33 1
        $this->exec($command);
34
    }
35
36
    /**
37
     * Get a revision
38
     */
39
    public function get_revision(string $revision) : array
40
    {
41
        $filename = $this->generate_filename();
42
        $lines = $this->read_handle('show ' . $revision . ':' . $this->relative_path($filename));
43
        $mapper = new midcom_helper_exporter_xml();
44
        return $mapper->data2array(implode("\n", $lines));
45
    }
46
47 1
    protected function load_history() : array
48
    {
49 1
        $filename = $this->generate_filename();
50 1
        if (!is_readable($filename)) {
51 1
            debug_add('file ' . $filename . ' is not readable, returning empty result', MIDCOM_LOG_INFO);
52 1
            return [];
53
        }
54
55 1
        $lines = $this->read_handle('log --shortstat --format=format:"%h%n%ae%n%at%n%s" ' . $this->relative_path($filename));
56 1
        $total = count($lines);
57 1
        $revisions = [];
58
59 1
        for ($i = 0; $i < $total; $i += 6) {
60 1
            [$user, $ip] = explode('@', $lines[$i + 1], 2);
61 1
            $stat = preg_replace('/.*?\d file changed/', '', $lines[$i + 4]);
62 1
            $stat = preg_replace('/, (\d+) .+?tions?\(([\+\-])\)/', '$2$1 ', $stat);
63
64 1
            $revisions[$lines[$i]] = [
65 1
                'revision' => $lines[$i],
66 1
                'date' => $lines[$i + 2],
67 1
                'lines' => $stat,
68 1
                'user' => $user,
69 1
                'ip' => $ip,
70 1
                'message' => $lines[$i + 3]
71 1
            ];
72
        }
73
74 1
        return $revisions;
75
    }
76
77 1
    protected function generate_filename() : string
78
    {
79 1
        $root = $this->config->get_rootdir();
80 1
        $initialized = true;
81 1
        if (!file_exists($root . '/.git')) {
82 1
            if ((count(scandir($root)) > 2)) {
83
                // This is probably an old rcs dir
84
                throw new midcom_error($root . ' is not empty. Run tools/rcs2git to convert');
85
            }
86 1
            $initialized = false;
87
        }
88 1
        $filename = parent::generate_filename();
89
90 1
        if (!$initialized) {
91 1
            $this->exec('init');
92 1
            $this->exec('config user.email "midcom.rcs@localhost"');
93 1
            $this->exec('config user.name "midcom.rcs"');
94
        }
95 1
        return $filename;
96
    }
97
98 1
    protected function read_handle(string $command) : array
99
    {
100 1
        return parent::read_handle('git -C ' . $this->config->get_rootdir() . ' ' . $command);
101
    }
102
103 1
    private function exec(string $command)
104
    {
105 1
        $prefix = 'git -C ' . $this->config->get_rootdir();
106 1
        if ($command != 'init') {
107
            // These help for the nested repo case
108 1
            $prefix .= ' --git-dir=' . $this->config->get_rootdir() . '/.git ' . ' --work-tree=' . $this->config->get_rootdir();
109
        }
110 1
        $this->run_command($prefix . ' ' . $command);
111
    }
112
113 1
    private function relative_path(string $filename) : string
114
    {
115 1
        $relative_path = substr($filename, strlen($this->config->get_rootdir()));
116 1
        return escapeshellarg(trim($relative_path, '/'));
117
    }
118
}
119