xref: /plugin/gitbacked/classes/GitBackedUtil.php (revision 2762023dfb29a64197cb442f664aa321f9f5bc87)
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 = array(
141            1 => array('pipe', 'w'),
142            2 => array('pipe', 'w'),
143        );
144        $ret = '';
145        $pipes = array();
146        // Using --git-dir rather than --absolute-git-dir for a wider git versions compatibility
147        //$command = Git::getBin()." rev-parse --absolute-git-dir";
148        $command = Git::getBin() . " rev-parse --git-dir";
149        //dbglog("GitBacked - Command: ".$command);
150        $resource = proc_open($command, $descriptorspec, $pipes, $path);
151        $stdout = stream_get_contents($pipes[1]);
152        $stderr = stream_get_contents($pipes[2]);
153        foreach ($pipes as $pipe) {
154            fclose($pipe);
155        }
156
157        $status = trim(proc_close($resource));
158        if ($status == 0) {
159            $repo_git_dir = trim($stdout);
160            //dbglog("GitBacked - $command: '".$repo_git_dir."'");
161            if (!empty($repo_git_dir)) {
162                if (strcmp($repo_git_dir, ".git") === 0) {
163                    // convert to absolute path based on this command execution directory
164                    $repo_git_dir = $path . '/' . $repo_git_dir;
165                }
166                $repo_path = dirname(realpath($repo_git_dir));
167                $doku_inc_path = dirname(realpath(DOKU_INC));
168                if (strlen($repo_path) < strlen($doku_inc_path)) {
169                    // This code should never be reached!
170                    // If we get here, then we are beyond DOKU_INC - so this not supposed to be for us!
171                    return '';
172                }
173                //dbglog('GitBacked - $repo_path: '.$repo_path);
174                if (file_exists($repo_path . "/.git") && is_dir($repo_path . "/.git")) {
175                    return $repo_path;
176                }
177            }
178        }
179        return '';
180    }
181}
182/* End of file */
183