Completed
Push — master ( c115fe...75ea5a )
by Andreas
22:20 queued 22:20
created

midcom_services_rcs_backend_rcs::update()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 20
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 13
nc 4
nop 1
dl 0
loc 20
ccs 13
cts 13
cp 1
crap 3
rs 9.8333
c 1
b 0
f 0
1
<?php
2
/**
3
 * @author tarjei huse
4
 * @package midcom.services.rcs
5
 * @copyright The Midgard Project, http://www.midgard-project.org
6
 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
7
 */
8
9
/**
10
 * @package midcom.services.rcs
11
 */
12
class midcom_services_rcs_backend_rcs extends midcom_services_rcs_backend
13
{
14 83
    protected function test_config()
15
    {
16 83
        parent::test_config();
17
18 83
        if (!is_executable("{$this->config->get_bin_prefix()}ci")) {
19
            throw new midcom_error("Cannot execute {$this->config->get_bin_prefix()}ci.");
20
        }
21
    }
22
23
    /**
24
     * Save a new revision
25
     */
26 75
    public function update(string $updatemessage = '')
27
    {
28 75
        $filename = $this->write_object();
29 75
        $rcsfilename = "{$filename},v";
30
31
        // Store user identifier and IP address to the update string
32 75
        $message = $_SERVER['REMOTE_ADDR'] . '|' . $updatemessage;
33 75
        $message = (midcom::get()->auth->user->id ?? 'NOBODY') . '|' . $message;
34 75
        $message = escapeshellarg($message);
35
36 75
        if (file_exists($rcsfilename)) {
37 36
            $this->exec('co -q -f -l ' . escapeshellarg($filename));
38 36
            $command = 'ci -q -m' . $message . " {$filename}";
39
        } else {
40 65
            $command = 'ci -q -i -t-' . $message . ' -m' . $message . " {$filename}";
41
        }
42 75
        $this->exec($command);
43
44 75
        if (file_exists($rcsfilename)) {
45 75
            chmod($rcsfilename, 0770);
46
        }
47
    }
48
49 4
    public function get_revision(string $revision) : array
50
    {
51 4
        $filepath = $this->generate_filename();
52
        try {
53 4
            $this->exec('co -q -f -r' . escapeshellarg(trim($revision)) . " {$filepath} 2>/dev/null");
54
        } catch (midcom_error $e) {
55
            $e->log();
56 4
        } finally {
57 4
            if (!file_exists($filepath)) {
58 4
                return [];
59
            }
60
        }
61
62 4
        $data = file_get_contents($filepath);
63 4
        $this->run_command("rm -f {$filepath}");
64
65 4
        $mapper = new midcom_helper_exporter_xml();
66 4
        return $mapper->data2array($data);
67
    }
68
69 7
    protected function load_history() : array
70
    {
71 7
        $filename = $this->generate_filename() . ',v';
72 7
        if (!is_readable($filename)) {
73 3
            debug_add('file ' . $filename . ' is not readable, returning empty result', MIDCOM_LOG_INFO);
74 3
            return [];
75
        }
76 7
        $lines = $this->read_handle($this->config->get_bin_prefix() . 'rlog "' . $filename . '" 2>&1');
77 7
        $total = count($lines);
78 7
        $revisions = [];
79
80 7
        for ($i = 0; $i < $total; $i++) {
81 7
            if (str_starts_with($lines[$i], "revision ")) {
82 7
                $history = $this->parse_history_entry($lines[$i], $lines[$i + 1], $lines[$i + 2]);
83 7
                $revisions[$history['revision']] = $history;
84
85 7
                $i += 3;
86 7
                while (   $i < $total
87 7
                        && !str_starts_with($lines[$i], '----')
88 7
                        && !str_starts_with($lines[$i], '=====')) {
89
                    $i++;
90
                }
91
            }
92
        }
93 7
        return $revisions;
94
    }
95
96 7
    private function parse_history_entry(string $line1, string $line2, string $line3) : array
97
    {
98
        // Create potentially empty defaults
99 7
        $history = ['date' => null, 'lines' => null, 'user' => null, 'ip' => null];
100
101
        // Revision number is in format
102
        // revision 1.11
103 7
        $history['revision'] = preg_replace('/(\d+\.\d+).*/', '$1', substr($line1, 9));
104
105
        // Entry metadata is in format
106
        // date: 2006/01/10 09:40:49;  author: www-data;  state: Exp;  lines: +2 -2
107
        // NOTE: Time here appears to be stored as UTC according to http://parand.com/docs/rcs.html
108 7
        $metadata_array = explode(';', $line2);
109 7
        foreach ($metadata_array as $metadata) {
110 7
            $metadata = trim($metadata);
111 7
            if (str_starts_with($metadata, 'date:')) {
112 7
                $history['date'] = strtotime(substr($metadata, 6));
113 7
            } elseif (str_starts_with($metadata, 'lines:')) {
114
                $history['lines'] = substr($metadata, 7);
115
            }
116
        }
117
118
        // Entry message is in format
119
        // user:27b841929d1e04118d53dd0a45e4b93a|84.34.133.194|message
120 7
        $message_array = explode('|', $line3);
121 7
        if (count($message_array) == 1) {
122
            $history['message'] = $message_array[0];
123
        } else {
124 7
            if ($message_array[0] != 'Object') {
125 7
                $history['user'] = $message_array[0];
126
            }
127 7
            $history['ip'] = $message_array[1];
128 7
            $history['message'] = $message_array[2];
129
        }
130 7
        return $history;
131
    }
132
133 79
    private function exec(string $command)
134
    {
135 79
        $this->run_command($this->config->get_bin_prefix() . $command);
136
    }
137
}
138