1<?php
2
3namespace woolfg\dokuwiki\plugin\gitbacked;
4
5/*
6 * GitBackedUtil.php
7 *
8 * PHP common utility function lib
9 *
10 * @package    GitBackedUtil.php
11 * @version    1.0
12 * @author     Markus Hoffrogge
13 * @copyright  Copyright 2023 Markus Hoffrogge
14 * @repo       https://github.com/woolfg/dokuwiki-plugin-gitbacked
15 */
16
17// phpcs:disable PSR1.Files.SideEffects.FoundWithSymbols
18// must be run within Dokuwiki
19if (!defined('DOKU_INC')) die();
20
21// ------------------------------------------------------------------------
22
23/**
24 * GitBacked Utility Class
25 *
26 * This class provides common utility functions.
27 *
28 * @class  GitBackedUtil
29 */
30class GitBackedUtil
31{
32    /**
33     * GitBacked temp directory
34     *
35     * @var string
36     */
37    protected static $temp_dir = '';
38
39    /**
40     * Checks, if a given path name is an absolute path or not.
41     * This function behaves like absolute path determination in dokuwiki init.php fullpath() method.
42     * The relevant code has been copied from there.
43     *
44     * @access  public
45     * @param   string $path    a file path name
46     * @return  bool
47     */
48    public static function isAbsolutePath($path)
49    {
50        $ret = false;
51
52        $iswin = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' || !empty($GLOBALS['DOKU_UNITTEST_ASSUME_WINDOWS']));
53        // check for the (indestructable) root of the path - keeps windows stuff intact
54        if ($path[0] == '/') {
55            $ret = true;
56        } elseif ($iswin) {
57            // match drive letter and UNC paths
58            if (preg_match('!^([a-zA-z]:)(.*)!', $path, $match)) {
59                $ret = true;
60            } elseif (preg_match('!^(\\\\\\\\[^\\\\/]+\\\\[^\\\\/]+[\\\\/])(.*)!', $path, $match)) {
61                $ret = true;
62            }
63        }
64
65        return $ret;
66    }
67
68    /**
69     * Returns the $path as is, if it is an absolute path.
70     * Otherwise it will prepend the base path appropriate
71     * to the type of DW instance.
72     *
73     * @access  public
74     * @param   string $path    a file path name
75     * @return  string          an appropriate absolute path
76     */
77    public static function getEffectivePath($path)
78    {
79        $ret = $path;
80
81        if (self::isAbsolutePath($ret)) {
82            return $ret;
83        }
84        if (defined('DOKU_FARM')) {
85            $ret = DOKU_CONF . '../' . $ret;
86        } else {
87            $ret = DOKU_INC . $ret;
88        }
89        return $ret;
90    }
91
92    /**
93     * Returns the temp dir for GitBacked plugin.
94     * It ensures that the temp dir will be created , if not yet existing.
95     *
96     * @access  public
97     * @return  string          the gitbacked temp directory name
98     */
99    public static function getTempDir()
100    {
101        if (empty(self::$temp_dir)) {
102            global $conf;
103            self::$temp_dir = $conf['tmpdir'] . '/gitbacked';
104            io_mkdir_p(self::$temp_dir);
105        }
106        return self::$temp_dir;
107    }
108
109    /**
110     * Creates a temp file and writes the $message to it.
111     * It ensures that the temp dir will be created , if not yet existing.
112     *
113     * @access  public
114     * @param   string $message the text message
115     * @return  string          the temp filename created
116     */
117    public static function createMessageFile($message)
118    {
119        $tmpfname = tempnam(self::getTempDir(), 'gitMessage_');
120        $handle = fopen($tmpfname, "w");
121        if (!empty($message)) {
122            fwrite($handle, $message);
123        }
124        fclose($handle);
125        return $tmpfname;
126    }
127
128    /**
129     * Determine closest git repository path for a given path as absolute PHP realpath().
130     * This search starts in $path - if $path does not contain .git,
131     * it will iterate the directories upwards as long as it finds a directory
132     * containing a .git folder.
133     *
134     * @access  public
135     * @return  string  the next git repo root dir as absolute PHP realpath()
136     *                  or empty string, if no git repo found.
137     */
138    public static function getClosestAbsoluteRepoPath($path)
139    {
140        $descriptorspec = [1 => ['pipe', 'w'], 2 => ['pipe', 'w']];
141        $pipes = [];
142        // Using --git-dir rather than --absolute-git-dir for a wider git versions compatibility
143        //$command = Git::getBin()." rev-parse --absolute-git-dir";
144        $command = Git::getBin() . " rev-parse --git-dir";
145        //dbglog("GitBacked - Command: ".$command);
146        $resource = proc_open($command, $descriptorspec, $pipes, $path);
147        $stdout = stream_get_contents($pipes[1]);
148        stream_get_contents($pipes[2]);
149        foreach ($pipes as $pipe) {
150            fclose($pipe);
151        }
152
153        $status = trim(proc_close($resource));
154        if ($status == 0) {
155            $repo_git_dir = trim($stdout);
156            //dbglog("GitBacked - $command: '".$repo_git_dir."'");
157            if (!empty($repo_git_dir)) {
158                if (strcmp($repo_git_dir, ".git") === 0) {
159                    // convert to absolute path based on this command execution directory
160                    $repo_git_dir = $path . '/' . $repo_git_dir;
161                }
162                $repo_path = dirname(realpath($repo_git_dir));
163                $doku_inc_path = dirname(realpath(DOKU_INC));
164                if (strlen($repo_path) < strlen($doku_inc_path)) {
165                    // This code should never be reached!
166                    // If we get here, then we are beyond DOKU_INC - so this not supposed to be for us!
167                    return '';
168                }
169                //dbglog('GitBacked - $repo_path: '.$repo_path);
170                if (file_exists($repo_path . "/.git") && is_dir($repo_path . "/.git")) {
171                    return $repo_path;
172                }
173            }
174        }
175        return '';
176    }
177}
178/* End of file */
179