|
|
<?php if ( !class_exists('Puc_v4p1_Vcs_Api') ):
abstract class Puc_v4p1_Vcs_Api { protected $tagNameProperty = 'name';
/** * @var string */ protected $repositoryUrl = '';
/** * @var mixed Authentication details for private repositories. Format depends on service. */ protected $credentials = null;
/** * @var string The filter tag that's used to filter options passed to wp_remote_get. * For example, "puc_request_info_options-slug" or "puc_request_update_options_theme-slug". */ protected $httpFilterName = '';
/** * Puc_v4p1_Vcs_Api constructor. * * @param string $repositoryUrl * @param array|string|null $credentials */ public function __construct($repositoryUrl, $credentials = null) { $this->repositoryUrl = $repositoryUrl; $this->setAuthentication($credentials); }
/** * @return string */ public function getRepositoryUrl() { return $this->repositoryUrl; }
/** * Figure out which reference (i.e tag or branch) contains the latest version. * * @param string $configBranch Start looking in this branch. * @return null|Puc_v4p1_Vcs_Reference */ abstract public function chooseReference($configBranch);
/** * Get the readme.txt file from the remote repository and parse it * according to the plugin readme standard. * * @param string $ref Tag or branch name. * @return array Parsed readme. */ public function getRemoteReadme($ref = 'master') { $fileContents = $this->getRemoteFile('readme.txt', $ref); if ( empty($fileContents) ) { return array(); }
$parser = new PucReadmeParser(); return $parser->parse_readme_contents($fileContents); }
/** * Get a branch. * * @param string $branchName * @return Puc_v4p1_Vcs_Reference|null */ abstract public function getBranch($branchName);
/** * Get a specific tag. * * @param string $tagName * @return Puc_v4p1_Vcs_Reference|null */ abstract public function getTag($tagName);
/** * Get the tag that looks like the highest version number. * (Implementations should skip pre-release versions if possible.) * * @return Puc_v4p1_Vcs_Reference|null */ abstract public function getLatestTag();
/** * Check if a tag name string looks like a version number. * * @param string $name * @return bool */ protected function looksLikeVersion($name) { //Tag names may be prefixed with "v", e.g. "v1.2.3".
$name = ltrim($name, 'v');
//The version string must start with a number.
if ( !is_numeric(substr($name, 0, 1)) ) { return false; }
//The goal is to accept any SemVer-compatible or "PHP-standardized" version number.
return (preg_match('@^(\d{1,5}?)(\.\d{1,10}?){0,4}?($|[abrdp+_\-]|\s)@i', $name) === 1); }
/** * Check if a tag appears to be named like a version number. * * @param stdClass $tag * @return bool */ protected function isVersionTag($tag) { $property = $this->tagNameProperty; return isset($tag->$property) && $this->looksLikeVersion($tag->$property); }
/** * Sort a list of tags as if they were version numbers. * Tags that don't look like version number will be removed. * * @param stdClass[] $tags Array of tag objects. * @return stdClass[] Filtered array of tags sorted in descending order. */ protected function sortTagsByVersion($tags) { //Keep only those tags that look like version numbers.
$versionTags = array_filter($tags, array($this, 'isVersionTag')); //Sort them in descending order.
usort($versionTags, array($this, 'compareTagNames'));
return $versionTags; }
/** * Compare two tags as if they were version number. * * @param stdClass $tag1 Tag object. * @param stdClass $tag2 Another tag object. * @return int */ protected function compareTagNames($tag1, $tag2) { $property = $this->tagNameProperty; if ( !isset($tag1->$property) ) { return 1; } if ( !isset($tag2->$property) ) { return -1; } return -version_compare(ltrim($tag1->$property, 'v'), ltrim($tag2->$property, 'v')); }
/** * Get the contents of a file from a specific branch or tag. * * @param string $path File name. * @param string $ref * @return null|string Either the contents of the file, or null if the file doesn't exist or there's an error. */ abstract public function getRemoteFile($path, $ref = 'master');
/** * Get the timestamp of the latest commit that changed the specified branch or tag. * * @param string $ref Reference name (e.g. branch or tag). * @return string|null */ abstract public function getLatestCommitTime($ref);
/** * Get the contents of the changelog file from the repository. * * @param string $ref * @param string $localDirectory Full path to the local plugin or theme directory. * @return null|string The HTML contents of the changelog. */ public function getRemoteChangelog($ref, $localDirectory) { $filename = $this->findChangelogName($localDirectory); if ( empty($filename) ) { return null; }
$changelog = $this->getRemoteFile($filename, $ref); if ( $changelog === null ) { return null; }
/** @noinspection PhpUndefinedClassInspection */ return Parsedown::instance()->text($changelog); }
/** * Guess the name of the changelog file. * * @param string $directory * @return string|null */ protected function findChangelogName($directory) { if ( empty($directory) || !is_dir($directory) || ($directory === '.') ) { return null; }
$possibleNames = array('CHANGES.md', 'CHANGELOG.md', 'changes.md', 'changelog.md'); $files = scandir($directory); $foundNames = array_intersect($possibleNames, $files);
if ( !empty($foundNames) ) { return reset($foundNames); } return null; }
/** * Set authentication credentials. * * @param $credentials */ public function setAuthentication($credentials) { $this->credentials = $credentials; }
public function isAuthenticationEnabled() { return !empty($this->credentials); }
/** * @param string $url * @return string */ public function signDownloadUrl($url) { return $url; }
/** * @param string $filterName */ public function setHttpFilterName($filterName) { $this->httpFilterName = $filterName; } }
endif;
|