Subversion Repositories php_utils

Rev

Rev 81 | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 81 Rev 82
Line 16... Line 16...
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
18
 * limitations under the License.
19
 */
19
 */
20
 
20
 
21
function git_get_latest_commit_message($git_dir) {
21
function git_get_latest_commit_id(string $git_dir): string {
22
        // First try an official git client
-
 
23
        $cmd = "git --git-dir=".escapeshellarg("$git_dir")." log -1 2>&1";
22
        // Note: The method "getTip()" of GLIP only implements "refs/heads/master" and "packed-refs" (but for packed-refs without "refs/remotes/origin/...")
24
        $ec = -1;
-
 
25
        $out = array();
-
 
26
        @exec($cmd, $out, $ec);
-
 
27
        $out = implode("\n",$out);
-
 
28
        if (($ec == 0) && ($out != '')) return $out;
-
 
29
 
23
 
30
        // If that failed, try to decode the binary files outselves
-
 
31
        $cont = @file_get_contents($git_dir.'/HEAD');
24
        $cont = @file_get_contents($git_dir . '/HEAD');
32
        if (preg_match('@ref: (.+)[\r\n]@', "$cont\n", $m) && file_exists($git_dir.'/'.$m[1])) {
25
        if (preg_match('@ref: (.+)[\r\n]@', "$cont\n", $m) && file_exists($git_dir . '/' . $m[1])) {
33
                // Example content of a .git folder file:
26
                // Example content of a .git folder file:
34
                // 091a5fa6b157be035e88f5d24aa329ba44d20d63
27
                // 091a5fa6b157be035e88f5d24aa329ba44d20d63
35
                // Not available
-
 
36
                $commit_object = trim(file_get_contents($git_dir.'/'.$m[1]));
28
                return trim(file_get_contents($git_dir . '/' . $m[1]));
-
 
29
        }
-
 
30
 
37
        } else if (file_exists($git_dir.'/refs/heads/master')) {
31
        if (file_exists($git_dir . '/refs/heads/master')) {
38
                // Missing at Plesk Git initial checkout, but available on update.
32
                // Missing at Plesk Git initial checkout, but available on update.
39
                $commit_object = trim(file_get_contents($git_dir.'/refs/heads/master'));
33
                return trim(file_get_contents($git_dir . '/refs/heads/master'));
-
 
34
        }
-
 
35
 
-
 
36
        if (file_exists($git_dir . '/packed-refs')) {
-
 
37
                // Example contents of the file:
-
 
38
                // # pack-refs with: peeled fully-peeled sorted
-
 
39
                // 5605bd539677494558470234266cb5885343e72b refs/remotes/origin/master
-
 
40
                // a3d910dd0cdca30827ae25b0f89045d8403b8843 refs/remotes/origin/patch-1
-
 
41
                $subpaths = ['refs/heads/master', 'refs/remotes/origin/master'];
-
 
42
                foreach ($subpaths as $subpath) {
-
 
43
                        $head = null;
-
 
44
                        $f = fopen($git_dir . '/packed-refs', 'rb');
-
 
45
                        flock($f, LOCK_SH);
-
 
46
                        while ($head === null && ($line = fgets($f)) !== false) {
-
 
47
                                if ($line[0] == '#')
-
 
48
                                        continue;
-
 
49
                                $parts = explode(' ', trim($line));
-
 
50
                                if (count($parts) == 2 && $parts[1] == $subpath)
-
 
51
                                        $head = $parts[0];
-
 
52
                        }
-
 
53
                        fclose($f);
-
 
54
                        if ($head !== null)
-
 
55
                                return $head;
-
 
56
                }
-
 
57
        }
-
 
58
 
40
        } else if (file_exists($git_dir.'/FETCH_HEAD')) {
59
        if (file_exists($git_dir . '/FETCH_HEAD')) {
41
                // Example content of a Plesk Git folder (fresh):
60
                // Example content of a Plesk Git folder (fresh):
42
                // 091a5fa6b157be035e88f5d24aa329ba44d20d63     not-for-merge   branch 'master' of https://github.com/danielmarschall/oidplus
61
                // 091a5fa6b157be035e88f5d24aa329ba44d20d63     not-for-merge   branch 'master' of https://github.com/danielmarschall/oidplus
43
                // 091a5fa6b157be035e88f5d24aa329ba44d20d63     not-for-merge   remote-tracking branch 'origin/trunk' of https://github.com/danielmarschall/oidplus
62
                // 091a5fa6b157be035e88f5d24aa329ba44d20d63     not-for-merge   remote-tracking branch 'origin/trunk' of https://github.com/danielmarschall/oidplus
44
                $cont = file_get_contents($git_dir.'/FETCH_HEAD');
63
                $cont = file_get_contents($git_dir . '/FETCH_HEAD');
45
                $commit_object = substr(trim($cont),0,40);
64
                return substr(trim($cont), 0, 40);
46
        } else {
-
 
47
                throw new Exception("Cannot detect last commit object");
-
 
48
        }
65
        }
49
 
66
 
-
 
67
        throw new Exception("Cannot detect latest Commit ID");
-
 
68
}
-
 
69
 
-
 
70
function git_get_latest_commit_message(string $git_dir): string {
-
 
71
        // First try an official git client
-
 
72
        $cmd = "git --git-dir=" . escapeshellarg("$git_dir") . " log -1 2>&1";
-
 
73
        $ec = -1;
-
 
74
        $out = array();
-
 
75
        @exec($cmd, $out, $ec);
50
        $objects_dir = $git_dir . '/objects';
76
        $out = implode("\n", $out);
-
 
77
        if (($ec == 0) && ($out != '')) return $out;
51
 
78
 
-
 
79
        // If that failed, try to decode the binary files ourselves
-
 
80
        $commit_object = git_get_latest_commit_id($git_dir);
-
 
81
        $objects_dir = $git_dir . '/objects';
52
 
82
 
53
        // Sometimes, objects are uncompressed, sometimes compressed in a pack file
83
        // Sometimes, objects are uncompressed, sometimes compressed in a pack file
54
        // Plesk initial checkout is compressed, but pulls via web interface
84
        // Plesk initial checkout is compressed, but pulls via web interface
55
        // save uncompressed files
85
        // save uncompressed files
56
 
86
 
-
 
87
        if (class_exists('ViaThinkSoft\Glip\Git')) {
-
 
88
                // https://github.com/danielmarschall/glip
-
 
89
                // composer require danielmarschall/glip
-
 
90
                $git = new ViaThinkSoft\Glip\Git($git_dir);
-
 
91
                $obj = $git->getObject(hex2bin($commit_object));
-
 
92
                return $obj->detail;
-
 
93
        } else {
-
 
94
                // Own implementation (the compressed read cannot handle delta objects yet)
-
 
95
 
57
        $uncompressed_file = $objects_dir . '/' . substr($commit_object,0,2) . '/' . substr($commit_object,2);
96
                $uncompressed_file = $objects_dir . '/' . substr($commit_object, 0, 2) . '/' . substr($commit_object, 2);
58
        if (file_exists($uncompressed_file)) {
97
                if (file_exists($uncompressed_file)) {
59
                // Read compressed data
98
                        // Read compressed data
60
                $compressed = file_get_contents($uncompressed_file);
99
                        $compressed = file_get_contents($uncompressed_file);
61
 
100
 
62
                // Uncompress
101
                        // Uncompress
63
                $uncompressed = @gzuncompress($compressed);
102
                        $uncompressed = @gzuncompress($compressed);
64
                if ($uncompressed === false) throw new Exception("Decompression failed");
103
                        if ($uncompressed === false) throw new Exception("Decompression failed");
65
 
104
 
66
                // The format is "commit <nnn>\0<Message>" where <nnn> is only a 3 digit number?!
105
                        // The format is "<type> <size>\0<Message>"
67
                $ary = explode(chr(0), $uncompressed);
106
                        list($hdr, $object_data) = explode("\0", $uncompressed, 2);
68
                $uncompressed = array_pop($ary);
107
                        // sscanf($hdr, "%s %d", $type, $object_size);
69
 
-
 
70
                return $uncompressed;
108
                        return $object_data;
71
        } else {
109
                } else {
72
                $pack_files = @glob($objects_dir.'/pack/pack-*.pack');
110
                        $pack_files = @glob($objects_dir . '/pack/pack-*.pack');
73
                $last_exception = 'No pack files found';
111
                        if ($pack_files) {
74
                if ($pack_files) foreach ($pack_files as $basename) {
112
                                foreach ($pack_files as $basename) {
75
                        $basename = substr(basename($basename),0,strlen(basename($basename))-5);
113
                                        $basename = substr(basename($basename), 0, strlen(basename($basename)) - 5);
76
                        try {
-
 
77
                                if (class_exists('ViaThinkSoft\Glip\Git')) {
-
 
78
                                        // https://github.com/danielmarschall/glip
-
 
79
                                        // composer require danielmarschall/glip
-
 
80
                                        $git = new ViaThinkSoft\Glip\Git($git_dir);
-
 
81
                                        $obj = $git->getObject(hex2bin($commit_object));
-
 
82
                                        return $obj->detail;
-
 
83
                                } else {
-
 
84
                                        // Own implementation (cannot read delta objects yet)
-
 
85
                                        return git_read_object($commit_object,
114
                                        return git_read_object($commit_object,
86
                                                $objects_dir.'/pack/'.$basename.'.idx',
115
                                                $objects_dir . '/pack/' . $basename . '.idx',
87
                                                $objects_dir.'/pack/'.$basename.'.pack'
116
                                                $objects_dir . '/pack/' . $basename . '.pack'
88
                                        );
117
                                        );
89
                                }
118
                                }
90
                        } catch (Exception $e) {
-
 
91
                                $last_exception = $e;
-
 
92
                        }
119
                        }
-
 
120
                        throw new Exception("No pack files found");
93
                }
121
                }
94
                throw new Exception($last_exception);
-
 
95
        }
122
        }
96
}
123
}
97
 
124
 
98
function git_read_object($object_wanted, $idx_file, $pack_file, $debug=false) {
125
function git_read_object(string $object_wanted, string $idx_file, string $pack_file, bool $debug = false): string {
99
        // More info about the IDX and PACK format: https://git-scm.com/docs/pack-format
126
        // More info about the IDX and PACK format: https://git-scm.com/docs/pack-format
100
 
127
 
101
        // Do some checks
128
        // Do some checks
102
        if (!preg_match('/^[0-9a-fA-F]{40}$/', $object_wanted, $m)) throw new Exception("Is not a valid object: $object_wanted");
129
        if (!preg_match('/^[0-9a-fA-F]{40}$/', $object_wanted, $m)) throw new Exception("Is not a valid object: $object_wanted");
103
        if (!file_exists($idx_file)) throw new Exception("Idx file $idx_file not found");
130
        if (!file_exists($idx_file)) throw new Exception("Idx file $idx_file not found");
Line 209... Line 236...
209
                        if ($debug) echo "Type = Invalid ($type)\n";
236
                        if ($debug) echo "Type = Invalid ($type)\n";
210
                        break;
237
                        break;
211
        }
238
        }
212
 
239
 
213
        // Find out the expected unpacked size
240
        // Find out the expected unpacked size
214
        $size = $size_info & 0xF /*0x00001111*/;
241
        $size = $size_info & 0xF /*0x00001111*/
-
 
242
        ;
215
        $shift_info = 4;
243
        $shift_info = 4;
216
        while ($size_info >= 0x80) {
244
        while ($size_info >= 0x80) {
217
                $size_info = unpack('C', fread($fp,1))[1];
245
                $size_info = unpack('C', fread($fp, 1))[1];
218
                $size = (($size_info & 0x7F) << $shift_info) + $size;
246
                $size = (($size_info & 0x7F) << $shift_info) + $size;
219
                $shift_info += 7;
247
                $shift_info += 7;