Completed
Push — master ( cbeceb...e8fccc )
by Andreas
17:05
created

midcom_services_rcs_backend_rcs::update()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 22
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 3

Importance

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