1:   2:   3:   4:   5:   6:   7:   8:   9:  10:  11:  12:  13:  14:  15:  16:  17:  18:  19:  20:  21:  22:  23:  24:  25:  26:  27:  28:  29:  30:  31:  32:  33:  34:  35:  36:  37:  38:  39:  40:  41:  42:  43:  44:  45:  46:  47:  48:  49:  50:  51:  52:  53:  54:  55:  56:  57:  58:  59:  60:  61:  62:  63:  64:  65:  66:  67:  68:  69:  70:  71:  72:  73:  74:  75:  76:  77:  78:  79:  80:  81:  82:  83:  84:  85:  86:  87:  88:  89:  90:  91:  92:  93:  94:  95:  96:  97:  98:  99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371: 372: 373: 374: 375: 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420: 421: 
<?php
    declare(strict_types=1);
    /**
     *  +------------------------------------------------------------+
     *  | apnscp                                                     |
     *  +------------------------------------------------------------+
     *  | Copyright (c) Apis Networks                                |
     *  +------------------------------------------------------------+
     *  | Licensed under Artistic License 2.0                        |
     *  +------------------------------------------------------------+
     *  | Author: Matt Saladna (msaladna@apisnetworks.com)           |
     *  +------------------------------------------------------------+
     */

    /**
     * Version control, CVS and subversion
     *
     * @package core
     */
    class Verco_Module extends Module_Skeleton
    {
        const TRAC_VERSION = '0.12.1';
        private $cvs_rpms = array('cvs');
        private $mercurial_rpms = array();
        private $git_rpms = array();
        private $svn_rpms = array('neon', 'neon-devel', 'subversion-devel', 'subversion', 'apr', 'apr-util', 'gnutls');

        /**
         * void __construct(void)
         *
         * @ignore
         */
        public function __construct()
        {
            parent::__construct();
            $this->user_srvc_cache = array();

            $this->exportedFunctions = array(
                'enable_svn'                      => PRIVILEGE_SITE,
                'enable_svn_backend'              => PRIVILEGE_SITE | PRIVILEGE_SERVER_EXEC,
                'enable_cvs'                      => PRIVILEGE_SITE,
                'enable_cvs_backend'              => PRIVILEGE_SITE | PRIVILEGE_SERVER_EXEC,
                'create_svn_repository'           => PRIVILEGE_SITE,
                'create_svn_repository_backend'   => PRIVILEGE_SITE | PRIVILEGE_SERVER_EXEC,
                'create_cvs_repository'           => PRIVILEGE_SITE,
                'create_cvs_repository_backend'   => PRIVILEGE_SITE | PRIVILEGE_SERVER_EXEC,
                'is_cvs_repository'               => PRIVILEGE_SITE,
                'is_svn_repository'               => PRIVILEGE_SITE,
                'delete_svn_repository'           => PRIVILEGE_SITE,
                'delete_svn_repository_backend'   => PRIVILEGE_SITE | PRIVILEGE_SERVER_EXEC,
                'delete_cvs_repository'           => PRIVILEGE_SITE,
                'delete_cvs_repository_backend'   => PRIVILEGE_SITE | PRIVILEGE_SERVER_EXEC,
                'cvs_enabled'                     => PRIVILEGE_SITE,
                'svn_enabled'                     => PRIVILEGE_SITE,
                'list_known_svn_repositories'     => PRIVILEGE_SITE,
                'list_known_cvs_repositories'     => PRIVILEGE_SITE,
                'get_local_installed_svn_version' => PRIVILEGE_SITE,
                'get_current_system_svn_version'  => PRIVILEGE_SITE,
                'get_current_system_cvs_version'  => PRIVILEGE_SITE,
                'get_local_installed_cvs_version' => PRIVILEGE_SITE,
                'get_trac_version'                => PRIVILEGE_ALL,
                'install_trac'                    => PRIVILEGE_SITE,
                'install_fcgi_bindings_backend'   => PRIVILEGE_SITE | PRIVILEGE_SERVER_EXEC,
                'trac_installed'                  => PRIVILEGE_SITE,
            );
        }

        /**
         * bool enable_svn (void)
         *
         * @throws PermissionError if pre-req SSH is not satisfied
         * @return bool
         */
        public function enable_svn()
        {
            if (!$this->check_for_shell()) {
                return new PermissionError("Pre-req SSH not satisfied");
            }
            return $this->query('verco_enable_svn_backend');
        }

        /**
         * bool enable_svn_backend (void)
         * {@link enable_svn}
         *
         * @return bool
         */
        public function enable_svn_backend()
        {
            // subversion is part of apollo platform
            if (version_compare(platform_version(), '4.5', '>=')) {
                return true;
            }
            foreach ($this->svn_rpms as $rpm) {
                $status = Util_Process::exec('/root/replicatedomain.sh ' . $rpm . ' ' . $this->domain);
            }

            return $status;
        }

        public function create_svn_repository($mPath)
        {
            $data = $this->query('verco_create_svn_repository_backend', $mPath);
            if ($data instanceof Exception) {
                return $data;
            }
            $db = \MySQL::initialize();
            $db->query("INSERT INTO `repository_paths`
                                                    (`id`,
                                                     `domain`,
                                                     `type`,
                                                     `date_installed`,
                                                     `path`)
                                             VALUES
                                                    (NULL,
                                                     '" . $this->domain . "',
                                                     'svn',
                                                     " . time() . ",
                                                     '" . $mPath . "');");

            return $data;

        }

        public function create_svn_repository_backend($mPath)
        {
            $status = Util_Process_Sudo::exec("svnadmin create %s", $mPath);
            return $status;


        }

        public function delete_svn_repository($mPath)
        {
            $data = $this->query('verco_delete_svn_repository_backend', $mPath);
            if ($data instanceof Exception) {
                return $data;
            }
            $db = \MySQL::initialize();
            $db->query("DELETE FROM repository_paths WHERE `domain` = '" . $this->domain . "' AND `type` = 'svn' AND path = '" . $mPath . "';");

            return true;

        }

        public function delete_svn_repository_backend($mPath)
        {
            $status = Util_Process_Sudo::exec('rm -rf %s',
                $mPath);
            return $status;

        }

        public function get_local_installed_svn_version()
        {
            if (!file_exists($this->domain_fs_path() . '/usr/bin/svn')) {
                return false;
            }

            $status = Util_Process::exec($this->domain_fs_path() . '/usr/bin/svn --version --quiet');
            return trim($status['output']);
        }

        public function get_current_system_svn_version()
        {
            $status = Util_Process::exec('env HOME="/" svn --version');
            preg_match('/version (.*)/', $status['output'], $info);
            return $info[1];
        }

        public function get_current_system_cvs_version()
        {
            $status = Util_Process::exec('cvs --version');
            preg_match('/\(CVS\) ([0-9\.]+)/', $status['output'], $info);
            return $info[1];
        }

        public function get_local_installed_cvs_version()
        {
            $status = Util_Process::exec($this->domain_fs_path() . '/usr/bin/cvs --version');
            preg_match('/\(CVS\) ([0-9\.]+)/', $status['output'], $info);
            return isset($info[1]) ? $info[1] : false;
        }

        /**
         * bool svn_enabled
         * Checks to see if Subversion is enabled for an account
         *
         * @return bool
         */
        public function svn_enabled()
        {
            return $this->check_for_shell() && file_exists('/home/virtual/' . $this->domain . '/usr/bin/svn');
        }

        public function is_svn_repository($mPath)
        {
            return false;

        }

        /**
         * array list_known_svn_repositories (void)
         *
         * @return array all known repositories, each index has an array with the values
         *               path and date (integer unix time)
         */
        public function list_known_svn_repositories()
        {
            $db = \MySQL::initialize();
            $q = $db->query("SELECT path, date_installed FROM `repository_paths` WHERE domain = '" . $this->domain . "' AND type = 'svn'");
            $repos = array();
            while ($row = $q->fetch_object()) {
                $repos[] = array('path' => $row->path, 'date' => $row->date_installed);
            }
            return $repos;
        }

        public function create_cvs_repository($mPath)
        {
            $status = $this->query('verco_create_cvs_repository_backend', $mPath);
            if ($status['output'] instanceof Exception) {
                return $status['output'];
            }
            $db = \MySQL::initialize();
            $stat = $db->query("INSERT INTO `repository_paths`
                                                    (`id`,
                                                     `domain`,
                                                     `type`,
                                                     `date_installed`,
                                                     `path`)
                                             VALUES
                                                    (NULL,
                                                     '" . $this->domain . "',
                                                     'cvs',
                                                     " . time() . ",
                                                     '" . $mPath . "');");
            return $status;
        }

        public function create_cvs_repository_backend($mPath)
        {
            $status = Util_Process_Sudo::exec('cvs -d %s init',
                $mPath);
            return $status;

        }

        public function delete_cvs_repository($mPath)
        {
            $data = $this->query('verco_delete_cvs_repository_backend', $mPath);
            if ($data instanceof Exception) {
                return $data;
            }
            $db = \MySQL::initialize();
            $db->query("DELETE FROM repository_paths WHERE `domain` = '" . $this->domain . "' AND `type` = 'cvs' AND path = '" . $mPath . "';");

            return true;

        }

        public function delete_cvs_repository_backend($mPath)
        {
            $status = Util_Process_Sudo::exec('rm -rf %s',
                $mPath);
            return $status;
        }

        /**
         * bool cvs_enabled (void)
         *
         * Checks to see if CVS is enabled
         *
         * @return bool
         */
        public function cvs_enabled()
        {
            return $this->check_for_shell() && file_exists('/home/virtual/' . $this->domain . '/usr/bin/cvs');
        }

        /**
         * bool enable_cvs (void)
         * Enables CVS support for an account
         *
         * @throw PermissionError pre-req SSH is not satisfied
         * @return bool
         */
        public function enable_cvs()
        {
            if (!$this->check_for_shell()) {
                return new PermissionError("Pre-req SSH not satisfied");
            }
            return $this->query('verco_enable_cvs_backend');
        }

        /**
         * bool enable_cvs_backend (void)
         * {@link enable_cvs_backend}
         *
         * @return bool
         */
        public function enable_cvs_backend()
        {
            // cvs is part of apollo platform
            if (version_compare(platform_version(), '4.5', '<')) {
                return true;
            }
            foreach ($this->cvs_rpms as $rpm) {
                $status = Util_Process::exec('/root/replicatedomain.sh ' . $rpm . ' ' . $this->domain);
            }

            return $status;
        }

        public function is_cvs_repository($mPath)
        {
            return false;
        }

        /**
         * array list_known_cvs_repositories (void)
         *
         * @return array all known repositories, each index has an array with the values
         *               path and date (integer unix time)
         */
        public function list_known_cvs_repositories()
        {
            $db = \MySQL::initialize();
            $q = $db->query("SELECT path, date_installed FROM `repository_paths` WHERE domain = '" . $this->domain . "' AND type = 'cvs'");
            $repos = array();
            while ($row = $q->fetch_object()) {
                $repos[] = array('path' => $row->path, 'date' => $row->date_installed);
            }

            return $repos;
        }

        public function install_trac()
        {
            if (!$this->check_for_shell()) {
                return new PermissionError("Pre-requisite SSH not satisfied");
            }
            if (!IS_CLI) {
                return $this->query('verco_install_trac');
            }

            // Prep filesystem
            Util_Process_Sudo::exec('[[ ! -z "$PYTHONPATH" && -d $PYTHONPATH ]] || mkdir -p $PYTHONPATH');

            $tmp = $this->domain_fs_path() . "/tmp";
            $trac = APNSCP_INSTALL_PATH . "/var/storehouse/trac/Trac-" . self::TRAC_VERSION . ".tar.gz ";
            if (version_compare(platform_version(), '4.5', '<')) {
                Util_Process::exec("sh /root/replicatedomain.sh subversion-python " . $this->domain);

                Util_Process::exec("tar -xvz --overwrite -C %s -f %s && chown -R %d:%d %s",
                    $tmp,
                    APNSCP_INSTALL_PATH . "/var/storehouse/trac/setuptools-0.6c9.tar.gz",
                    $this->user_id,
                    $this->group_id,
                    $tmp . '/setuptools-0.6c9'
                );
                Util_Process_Sudo::exec('cd /tmp/setuptools-0.6c9/ && python setup.py install --prefix=/usr/local');

                Util_Process::exec("tar -xvz --overwrite -C %s -f %s && chown -R %d:%d %s",
                    $tmp,
                    APNSCP_INSTALL_PATH . "/var/storehouse/trac/pysqlite-2.3.3.tar.gz",
                    $this->user_id,
                    $this->group_id,
                    $tmp . '/pysqlite-2.3.3'
                );
                Util_Process_Sudo::exec('cd /tmp/pysqlite-2.3.3/ && python setup.py install --prefix=/usr/local');

            }

            Util_Process::exec("tar -xvz --overwrite -C %s -f %s && chown -R %d:%d %s",
                $tmp,
                APNSCP_INSTALL_PATH . "/var/storehouse/trac/clearsilver-0.10.4.tar.gz",
                $this->user_id,
                $this->group_id,
                $tmp . '/clearsilver-0.10.4'
            );

            Util_Process_Sudo::exec('cd /tmp/clearsilver-0.10.4/ && ./configure --prefix=/usr/local --disable-ruby && make && make install');

            Util_Process::exec("tar -xvz --overwrite -C %s -f %s && chown -R %d:%d %s",
                $tmp,
                $trac,
                $this->user_id,
                $this->group_id,
                $tmp . '/Trac-' . self::TRAC_VERSION

            );

            Util_Process_Sudo::exec('cd %s && python setup.py install --prefix=/usr/local',
                '/tmp/Trac-' . self::TRAC_VERSION);
            Util_Process::exec("rm -rf %s/{pysqlite-2.3.3,clearsilver-0.10.4,setuptools-0.6c9,Trac-" . self::TRAC_VERSION . "}/",
                $tmp);
            return $this->trac_installed();

        }

        public function trac_installed()
        {
            return file_exists($this->domain_fs_path() . '/usr/local/bin/trac-admin');
        }

        public function get_trac_version()
        {
            return self::TRAC_VERSION;
        }

        private function check_for_shell()
        {
            return $this->get_service_value('ssh', 'enabled');
        }


    }

?>