diff options
| author | Christian Weiske <cweiske@cweiske.de> | 2012-09-21 10:33:24 +0200 |
|---|---|---|
| committer | Christian Weiske <cweiske@cweiske.de> | 2012-09-21 10:33:24 +0200 |
| commit | 5d065586f4c16c0ec6510dba97b0d5facb859d75 (patch) | |
| tree | 9ac780960aaa01e92235c72443193b585e23f3f9 | |
| parent | 9f4d00eb634cbf75db2143a62ce8733e901b14a8 (diff) | |
| parent | 6dd1eeafade7105c0785340a43877a8d63793892 (diff) | |
| download | phorkie-5d065586f4c16c0ec6510dba97b0d5facb859d75.tar.gz phorkie-5d065586f4c16c0ec6510dba97b0d5facb859d75.zip | |
Merge branch 'master' into milestone
| -rw-r--r-- | ChangeLog | 4 | ||||
| -rw-r--r-- | data/templates/fork-remote-multiple.htm | 27 | ||||
| -rw-r--r-- | data/templates/fork-remote-new.htm | 12 | ||||
| -rw-r--r-- | data/templates/fork-remote.htm | 17 | ||||
| -rw-r--r-- | data/templates/new.htm | 3 | ||||
| -rw-r--r-- | data/templates/repo-sidebar-list.htm | 2 | ||||
| -rw-r--r-- | src/phorkie/ForkRemote.php | 114 | ||||
| -rw-r--r-- | src/phorkie/Forker.php | 44 | ||||
| -rw-r--r-- | src/phorkie/Renderer/Geshi.php | 2 | ||||
| -rw-r--r-- | src/phorkie/Repository.php | 7 | ||||
| -rw-r--r-- | www/.htaccess | 1 | ||||
| -rw-r--r-- | www/fork-remote.php | 45 | ||||
| -rw-r--r-- | www/fork.php | 17 |
13 files changed, 278 insertions, 17 deletions
@@ -1,3 +1,7 @@ +2012-09-19 Christian Weiske <cweiske@bogo> + + * Implement request #13: remote forking support + 2012-09-19 Christian Weiske <cweiske@cweiske.de> * Implement request #12: add link rel="vcs-git" diff --git a/data/templates/fork-remote-multiple.htm b/data/templates/fork-remote-multiple.htm new file mode 100644 index 0000000..f5a95b2 --- /dev/null +++ b/data/templates/fork-remote-multiple.htm @@ -0,0 +1,27 @@ +<form method="post" action="/fork-remote" enctype="multipart/form-data" class="well form-inline form-horizontal"> + <div class="control-group"> + <p> + The URL you provided contains links to several Git repositories. + Select one of them. + </p> + <select size="{{urlselsize}}" name="remote_url" id="sel-remote_url" style="width:100%"> + {% for grouptitle, groupurls in urls %} + {% if groupurls|length == 1 %} + <option value="{{groupurls.0}}">{{grouptitle}}</option> + {% else %} + <optgroup label="{{grouptitle}}"> + {% for url in groupurls %} + <option value="{{url}}">{{url}}</option> + {% endfor %} + </optgroup> + {% endif %} + {% endfor %} + </select> + </div> + <div style="text-align: right"> + <button type="submit" class="btn btn-primary"> + <i class="icon-share icon-white"></i> Fork + </button> + </div> + +</form>
\ No newline at end of file diff --git a/data/templates/fork-remote-new.htm b/data/templates/fork-remote-new.htm new file mode 100644 index 0000000..6b48ffe --- /dev/null +++ b/data/templates/fork-remote-new.htm @@ -0,0 +1,12 @@ +<form method="post" action="/fork-remote" enctype="multipart/form-data" class="well form-inline"> + <p> + <strong>Copy a paste from a remote server:</strong> + Just paste the website or git clone URL. + </p> + + <button type="submit" class="btn btn-primary" style="float: right"> + <i class="icon-share icon-white"></i> Fork remote paste + </button> + <label for="remote-url">Remote paste URL</label> + <input type="text" name="remote_url" id="remote-url" value="{{remote_url}}" class="span5"/> +</form> diff --git a/data/templates/fork-remote.htm b/data/templates/fork-remote.htm new file mode 100644 index 0000000..f651661 --- /dev/null +++ b/data/templates/fork-remote.htm @@ -0,0 +1,17 @@ +{% extends "base.htm" %} +{% block title %}Fork remote paste{% endblock %} + +{% block content %} + {% include 'fork-remote-new.htm' %} + + {% if error %} + <div class="alert alert-error"> + {{error}} + </div> + {% endif %} + + {% if urls %} + {% include 'fork-remote-multiple.htm' %} + {% endif %} + +{% endblock %} diff --git a/data/templates/new.htm b/data/templates/new.htm index 89c2fe0..8029b8c 100644 --- a/data/templates/new.htm +++ b/data/templates/new.htm @@ -20,6 +20,9 @@ </div> </form> + +{% include 'fork-remote-new.htm' %} + <script type="application/javascript"> $(document).ready(function() { initEdit(); diff --git a/data/templates/repo-sidebar-list.htm b/data/templates/repo-sidebar-list.htm index 568656e..ed262ac 100644 --- a/data/templates/repo-sidebar-list.htm +++ b/data/templates/repo-sidebar-list.htm @@ -2,5 +2,5 @@ <a href="{{repo.getLink('display')}}"> {{repo.getTitle}} </a><br/> - <span title="{{repo.crdate|date('c')}}">{{dh.get(repo.crdate)}}</span> +    <span title="{{repo.crdate|date('c')}}">{{dh.get(repo.crdate)}}</span> </li> diff --git a/src/phorkie/ForkRemote.php b/src/phorkie/ForkRemote.php new file mode 100644 index 0000000..524255a --- /dev/null +++ b/src/phorkie/ForkRemote.php @@ -0,0 +1,114 @@ +<?php +namespace phorkie; + +class ForkRemote +{ + protected $url; + + /** + * Array with keys (URL title) and values (arrays of urls) + * Only supported URLs are included. + * + * @var array + */ + protected $arGitUrls; + + + + public function __construct($url) + { + $this->url = $url; + } + + public function parse() + { + $scheme = parse_url($this->url, PHP_URL_SCHEME); + switch ($scheme) { + case 'git': + //clearly a git url + $this->arGitUrls = array(array($this->url)); + return true; + + case 'ssh': + //FIXME: maybe loosen this when we know how to skip the + //"do you trust this server" question of ssh + $this->error = 'ssh:// URLs are not supported'; + return false; + + case 'http': + case 'https': + return $this->extractUrlsFromHtml($this->url); + } + + $this->error = 'Unknown URLs scheme: ' . $scheme; + return false; + } + + protected function extractUrlsFromHtml($url) + { + //HTML is not necessarily well-formed, and Gitorious has many problems + // in this regard + //$sx = simplexml_load_file($url); + libxml_use_internal_errors(true); + $sx = simplexml_import_dom(\DomDocument::loadHtmlFile($url)); + $elems = $sx->xpath('//*[@rel="vcs-git"]'); + + $count = $anonymous = 0; + foreach ($elems as $elem) { + if (!isset($elem['href'])) { + continue; + } + $str = (string)$elem; + if (isset($elem['title'])) { + //<link href=".." rel="vcs-git" title="title" /> + $title = (string)$elem['title']; + } else if ($str != '') { + //<a href=".." rel="vcs-git">title</a> + $title = $str; + } else { + $title = 'Unnamed repository #' . ++$anonymous; + } + $url = (string)$elem['href']; + if ($this->isSupported($url)) { + ++$count; + $this->arGitUrls[$title][] = $url; + } + } + + return $count > 0; + } + + /** + * Iterate through all git urls and return one if there is only + * one supported one. + * + * @return mixed Boolean false or string + */ + public function getUniqueGitUrl() + { + $nFound = 0; + foreach ($this->arGitUrls as $title => $arUrls) { + foreach ($arUrls as $url) { + $nFound++; + $uniqueUrl = $url; + } + } + + if ($nFound == 1) { + return $uniqueUrl; + } + return false; + } + + public function getGitUrls() + { + return $this->arGitUrls; + } + + public function isSupported($url) + { + return parse_url($url, PHP_URL_SCHEME) == 'git'; + } +} + +?> diff --git a/src/phorkie/Forker.php b/src/phorkie/Forker.php new file mode 100644 index 0000000..3425a72 --- /dev/null +++ b/src/phorkie/Forker.php @@ -0,0 +1,44 @@ +<?php +namespace phorkie; + +class Forker +{ + public function forkLocal($repo) + { + $new = $this->fork($repo->gitDir); + \copy($repo->gitDir . '/description', $new->gitDir . '/description'); + return $new; + } + + public function forkRemote($url) + { + $new = $this->fork($url); + file_put_contents( + $new->gitDir . '/description', + 'Fork of ' . $url + ); + return $new; + } + + + protected function fork($pathOrUrl) + { + $rs = new Repositories(); + $new = $rs->createNew(); + $vc = $new->getVc(); + \rmdir($new->gitDir);//VersionControl_Git wants an existing dir, git clone not + $vc->getCommand('clone') + //this should be setOption, but it fails with a = between name and value + ->addArgument('--separate-git-dir') + ->addArgument($GLOBALS['phorkie']['cfg']['gitdir'] . '/' . $new->id . '.git') + ->addArgument($pathOrUrl) + ->addArgument($new->workDir) + ->execute(); + foreach (\glob($new->gitDir . '/hooks/*') as $hookfile) { + \unlink($hookfile); + } + return $new; + } +} + +?> diff --git a/src/phorkie/Renderer/Geshi.php b/src/phorkie/Renderer/Geshi.php index 2010ead..21d36c2 100644 --- a/src/phorkie/Renderer/Geshi.php +++ b/src/phorkie/Renderer/Geshi.php @@ -28,7 +28,7 @@ class Renderer_Geshi } return '<div class="code">' - . $geshi->parse_code() + . str_replace(' ', ' ', $geshi->parse_code()) . '</div>'; } diff --git a/src/phorkie/Repository.php b/src/phorkie/Repository.php index 4ac5ae7..25b049c 100644 --- a/src/phorkie/Repository.php +++ b/src/phorkie/Repository.php @@ -310,6 +310,13 @@ class Repository $commit->committerName = $arOutput[$current + 2]; $commit->committerEmail = $arOutput[$current + 3]; + if (substr($arOutput[$current + 4], 0, 1) != ' ') { + //commit without changed lines + $arCommits[] = $commit; + $current += 4; + continue; + } + $arLineParts = explode(' ', trim($arOutput[$current + 4])); $commit->filesChanged = $arLineParts[0]; $commit->linesAdded = $arLineParts[3]; diff --git a/www/.htaccess b/www/.htaccess index 1f03fac..03bbf60 100644 --- a/www/.htaccess +++ b/www/.htaccess @@ -13,6 +13,7 @@ RewriteRule ^([0-9]+)/rev/(.+)$ /revision.php?id=$1&rev=$2 RewriteRule ^([0-9]+)/rev-raw/(.+)/(.+)$ /raw.php?id=$1&rev=$2&file=$3 RewriteRule ^([0-9]+)/tool/([^/]+)/(.+)$ /tool.php?id=$1&tool=$2&file=$3 +RewriteRule ^fork-remote$ /fork-remote.php RewriteRule ^new$ /new.php RewriteRule ^list$ /list.php diff --git a/www/fork-remote.php b/www/fork-remote.php new file mode 100644 index 0000000..374c8b8 --- /dev/null +++ b/www/fork-remote.php @@ -0,0 +1,45 @@ +<?php +namespace phorkie; +/** + * Fork a remote repository. + * Displays a URL selection form when multiple git urls have been found + */ +require_once 'www-header.php'; + +$error = null; +$urls = null; +if (isset($_POST['remote_url'])) { + $fr = new ForkRemote($_POST['remote_url']); + if (false === $fr->parse()) { + //no url found + $error = 'No git:// clone URL found'; + } else if (false !== ($gitUrl = $fr->getUniqueGitUrl())) { + $forker = new Forker(); + $new = $forker->forkRemote($gitUrl); + redirect($new->getLink('display')); + } else { + //multiple urls found + $urls = $fr->getGitUrls(); + } +} + +$selsize = 0; +if (is_array($urls)) { + foreach ($urls as $group) { + ++$selsize; + if (count($group) > 1) { + $selsize += count($group); + } + } +} + +render( + 'fork-remote', + array( + 'remote_url' => isset($_POST['remote_url']) ? $_POST['remote_url'] : '', + 'error' => $error, + 'urls' => $urls, + 'urlselsize' => $selsize, + ) +); +?> diff --git a/www/fork.php b/www/fork.php index 6c96a6a..d8a24a2 100644 --- a/www/fork.php +++ b/www/fork.php @@ -13,21 +13,8 @@ if ($_SERVER['REQUEST_METHOD'] !== 'POST') { $repo = new Repository(); $repo->loadFromRequest(); -$rs = new Repositories(); -$new = $rs->createNew(); -$vc = $new->getVc(); -\rmdir($new->gitDir);//VersionControl_Git wants an existing dir, git clone not -$vc->getCommand('clone') - //this should be setOption, but it fails with a = between name and value - ->addArgument('--separate-git-dir') - ->addArgument($GLOBALS['phorkie']['cfg']['gitdir'] . '/' . $new->id . '.git') - ->addArgument($repo->gitDir) - ->addArgument($new->workDir) - ->execute(); -\copy($repo->gitDir . '/description', $new->gitDir . '/description'); -foreach (\glob($new->gitDir . '/hooks/*') as $hookfile) { - \unlink($hookfile); -} +$forker = new Forker(); +$new = $forker->forkLocal($repo); //FIXME: where to put fork source link? redirect($new->getLink('display')); |
