Source

VersionControl_Hg / src / VersionControl / Hg / Command / Clone.php

The default branch has multiple heads

<?php
/**
 * Contains the definition of the VersionControl_Hg_Repository_Command_Clone
 * class
 *
 * PHP version 5
 *
 * @category   VersionControl
 * @package    Hg
 * @subpackage Command
 * @author     Michael Gatto <mgatto@lisantra.com>
 * @copyright  2011 Lisantra Technologies, LLC
 * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link       http://pear.php.net/package/VersionControl_Hg
 */

/**
 * Clone a repository to a destination
 *
 * Usage:
 * <code>
 * $hg = new VersionControl_Hg('/path/to/repo');
 * $hg->clone('http://url/to/repo')->to('/path/to/clone')->run();
 * </code>
 *
 * PHP version 5
 *
 * @category   VersionControl
 * @package    Hg
 * @subpackage Command
 * @author     Michael Gatto <mgatto@lisantra.com>
 * @copyright  2011 Lisantra Technologies, LLC
 * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link       http://pear.php.net/package/VersionControl_Hg
 */
class VersionControl_Hg_Command_Clone
    extends VersionControl_Hg_Command_Abstract
        implements VersionControl_Hg_Command_Interface
{
    /**
     * The name of the mercurial command implemented here
     *
     * @var string
     */
    protected $command = 'clone';

    /**
     * Required options for this specific command. These may not be required
     * by Mercurial itself, but are required for the proper functioning of
     * this package.
     *
     * @var mixed
     */
    protected $required_options = array(
        'noninteractive' => null,
        'files' => null,
    );

    /**
     * Permissable options.
     *
     * The actual option must be the key, while 'null' is a value here to
     * accommodate the current implementation of setting options.
     *
     * @var mixed
     */
    protected $allowed_options = array(
        /* --pull is used for safety since HG automatically uses hardlinks for
         repo data, although on some fs's, its not safe (eg. AFS) */
        'pull' => null,
        'sparse' => null,
        'updaterev' => null,
        'branch' => null,
    );

    /**
     * The path in which Mercurial will create the new repository
     *
     * @var string
     */
    protected $cloned_path;

    /**
     * Constructor
     *
     * @param mixed             $params One or more parameters to the command
     * @param VersionControl_Hg $hg     Instance of the base object
     *
     * @return void
     */
    public function __construct($params = null, VersionControl_Hg $hg)
    {
var_dump($params);
        /* Make $hg available to option methods */
        $this->hg = $hg;

        /* check if a repository has been designated already or not */
        $cloned_path = $this->hg->repository->getPath();

        if ( empty($cloned_path) ) {
            /* are the argument(s) correctly formed? */
            if ( (array_key_exists(0, $params)) && (! empty($params[0])) ) {
                /* if its an array, check for the 'repository' key */
                if ( (is_array($params[0])) && (! array_key_exists('repository', $params[0]))) {
                    throw new VersionControl_Hg_Command_Exception(
                        VersionControl_Hg_Command_Exception::BAD_ARGUMENT,
                        "The repository must be defined either at
                         instantiation, as a string path arugment to clone()
                         or as the 'repository' key in an array of options."
                    );

                    /* should always be called so we have a full array of
                     * valid options */
                    $this->setOptions($params);

                } elseif ( is_scalar($params[0]) ) {
                    /* if scalar, we have to assume its a path.
                     * This is a psuedo-hack because clone has no arugment prefix;
                     * our current inmplementation of 'files' doesn't give
                     * one = cool! */
                    /* $params works instead of $params[0] because $params is
                     * an array and now $files wants an array! */
                    //$this->addOption('files', $params);
                    $this->repository($params[0]);
                }
            }

        } else {
            /* should always be called so we have a full array of valid options */
            $this->setOptions($params);
        }
    }

    /**
     * Execute the command and return the results.
     *
     * @param mixed             $params Options passed to the Log command
     * @param VersionControl_Hg $hg     Instance of the base object
     *
     * @return string
     */
    public function execute(array $params = null, VersionControl_Hg $hg = null)
    {
        /* Validate */
        $files = $this->getOption('files');
        /* the destination of the cloned repo must be index 1 */
        $cloned_path = $files[1];

        if (! $this->directory_exists($cloned_path) ) {
            //@TODO remove since it causes problems on multithreaded servers
            /* kill any umasks. */
            //umask(0);

            //refuse bad fs names
            //$except = array('\\', '/', ':', '*', '?', '"', '<', '>', '|');

            //Please note that when specifying the recursive option the
            // function returns false anyway if the directory already exists.
            //Octal permissions are ignored on Windows
            if (! mkdir($cloned_path, 0755, true) ) {
                throw new VersionControl_Hg_Command_Exception(
                    VersionControl_Hg_Command_Exception::BAD_ARGUMENT,
                    "PHP encountered an error while trying to create the
                     directory '{$cloned_path}'. "
                );
            }

            /* This works around some umask issues */
            chmod($cloned_path, 0755);
        } //clearstatcache()

        if ( ! is_writable($cloned_path) ) {
            throw new VersionControl_Hg_Command_Exception(
                VersionControl_Hg_Command_Exception::BAD_ARGUMENT,
                "The directory '{$cloned_path}' is not writable, but must be. "
            );
        }

        if ( ! $this->directory_is_empty($cloned_path) ) {
            throw new VersionControl_Hg_Command_Exception(
                VersionControl_Hg_Command_Exception::BAD_ARGUMENT,
                "The directory '{$cloned_path}' is not empty, but must be. "
            );
        }

        /* take care of options passed into run() as such:
         * $hg->clone('/path/')->run('verbose'));
         */
        if ( ! empty($params) ) {
            $this->setOptions($params);
        }

        /* --noninteractive is required since issuing the command is
         * unattended by nature of using this package.
        */
        $this->addOptions(
            array(
                'noninteractive' => null,
            )
        );

        /* Despite its being so not variable, we need to set the command string
         * only after manually setting options and other command-specific data */
        $this->setCommandString();
var_dump($this->getCommandString());
die;
        /* no var assignment, since 2nd param holds output */
        exec($this->command_string, $this->output, $this->status);

        if ( $this->status !== 0 ) {
            throw new VersionControl_Hg_Command_Exception(
                VersionControl_Hg_Command_Exception::COMMANDLINE_ERROR
            );
        }
        $repository = VersionControl_Hg_Container_Repository::getInstance();
        $repository->setPath($cloned_path);

        return $this->hg->repository;
    }

    /**
     * Tells Mercurial to use the pull functionality to copy metadata.
     *
     * @return VersionControl_Hg_Command_Abstract
     */
    public function pull()
    {
        $this->addOption('pull', null);

        /* For the fluent API */
        return $this;
    }

    /**
     * Tells Mercurial to not create a working copy.
     *
     * @return VersionControl_Hg_Command_Abstract
     */
    public function sparse()
    {
        $this->addOption('noupdate', null);

        /* For the fluent API */
        return $this;
    }

    /**
     * Sets the destination to which the old repository will be cloned.
     *
     * @param string $path Destination of the clone operation
     *
     * @return VersionControl_Hg_Command_Abstract
     */
    public function to($path)
    {
        $files = $this->getOption('files');

        /* the repository to clone MUST be the first files item */
        $files[1] = $path;
        $this->addOption('files', $files);

        /* For the fluent API */
        return $this;
    }

    /**
     * Specifies the repository for when $hg is initiated without an existing repository
     *
     * Allows calls such as:
     * <code>
     * $hg->clone()->repository('http://url/to/repo')->to('/path/to/clone')->run();
     * </code>
     *
     * @param string $path Destination of the clone operation
     *
     * @return VersionControl_Hg_Command_Abstract
     */
    public function repository($path)
    {
        $files = $this->getOption('files');
//var_dump($path, $files);
//die;
        /* the repository to clone MUST be the first files item */
        /* what if they called to() first or specified 'to'=> before 'repository' => ? */
        if ( is_array($files) && array_key_exists('0', $files) ) {
            /* reassign before its overwritten below... */
            $file[1] = $files[0];
        }

        $files[0] = $path;
        $this->addOption('files', $files);

        /* For the fluent API */
        return $this;
    }

    /**
     * Specifies the revision or tag clone from the repository
     *
     * Usage:
     * <code>$hg->clone()->revision(7)->run();</code>
     * or
     * <code>$hg->clone()->revision('cde1256adc443a3')->run();</code>
     * or
     * <code>$hg->clone(array('revision' => 7 ))->to('/path/to)->run();</code>
     *
     * @param string $revision is the optional revision to archive
     *
     * @return void
     */
    public function revision($revision = 'tip')
    {
        $this->addOption('updaterev', $revision);

        /* for the fluent API */
        return $this;
    }

    /**
     * Specifies the branch to restrict the clone operation to
     *
     * Usage:
     * <code>$hg->clone()->branch('')->to('/path/to)->run();</code>
     * or
     * <code>$hg->clone(array('repository' => '', 'branch' => ''))->to('/path/to')->run();</code>
     *
     * @param string $branch is the branch to clone, and only that branch
     *
     * @return VersionControl_Hg_Command_Abstract
     */
    public function branch($branch= 'default')
    {
        $this->addOption('branch', $branch);

        /* For the fluent API */
        return $this;
    }

    /**
     * Confirm that the path exists
     *
     * @param string $path The path the repository should be created at
     *
     * @return boolean
     */
    protected function directory_exists($path)
    {
        $directory_exists = true;

        if (! is_dir($path) ) {
            //So, is it a file? Do we care?

            $directory_exists = false;
        }

        /* for the fluent API */
        return $directory_exists;
    }

    /**
     * Confirm that the path exists
     *
     * @param string $path The path the repository should be created at
     *
     * @return boolean
     */
    protected function directory_is_empty($path)
    {
        $directory_is_empty = true;

        $files_in_dir = scandir($path);

        /* ccount for . and .. */
        if ( count($files_in_dir) > 2 ) {
            $directory_is_empty = false;
        }

        /* for the fluent API */
        return $directory_is_empty;
    }

}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.