Files
newznab-tmux/nntmux/utility/Versions.php
T
2017-08-11 10:03:35 +02:00

322 lines
8.5 KiB
PHP
Executable File

<?php
namespace nntmux\utility;
if (!defined('GIT_PRE_COMMIT')) {
define('GIT_PRE_COMMIT', false);
}
use nntmux\ColorCLI;
class Versions
{
/**
* These constants are bitwise for checking what was changed.
*/
const UPDATED_GIT_COMMIT = 1;
const UPDATED_GIT_TAG = 2;
const UPDATED_SQL_DB_PATCH = 4;
const UPDATED_SQL_FILE_LAST = 8;
/**
* @var Git instance variable.
*/
public $git;
/**
* @var ColorCLI
*/
public $out;
/**
* @var int
*/
protected $_changes = 0;
/**
* @var null|string
*/
protected $_filespec;
/**
* @var string highest tag value
*/
protected $_gitHighestTag;
/**
* @var array of stable branches.
*/
protected $_stable = ['0.x'];
/**
* Shortcut to the newznab->versions node to make method work shorter.
* @var object SimpleXMLElement
*/
protected $_vers;
/**
* @var object simpleXMLElement
*/
protected $_xml;
/**
* Class constructor initialises the SimpleXML object and sets a few properties.
* @param string $filepath Optional filespec for the XML file to use. Will use default otherwise.
*
* @throws \Exception If the XML is invalid.
* @throws \RuntimeException If version file does not exist.
*/
public function __construct($filepath = null)
{
if (empty($filepath)) {
if (defined('NN_VERSIONS')) {
$filepath = NN_VERSIONS;
}
}
if (!file_exists($filepath)) {
throw new \RuntimeException("Versions file '$filepath' does not exist!'");
}
$this->_filespec = $filepath;
$this->out = new ColorCLI();
$this->git = new Git();
$this->getValidVersionsFile();
}
public function changes(): int
{
return $this->_changes;
}
/**
* Run all checks
* @param boolean $update Whether the XML should be updated by the check.
* @return boolean True if any of the checks actually caused an update (not if it indicated one was needed), flase otherwise
*/
public function checkAll($update = true)
{
$this->checkGitTag($update);
$this->checkSQLDb($update);
$this->checkGitCommit($update);
return $this->hasChanged();
}
/**
* Checks the git commit number against the XML's stored value.
* @param boolean $update Whether the XML should be updated by the check.
* @return integer|boolean The new git commit number, or false.
*/
public function checkGitCommit($update = true)
{
// Since Dec 2014 we no longer maintain the git commit count in the XML file, as it is no
// longer used in the code base.
if ((int)$this->_vers->sql->db >= 307) {
return 0;
}
$count = $this->git->commits();
if (GIT_PRE_COMMIT === true || $this->_vers->git->commit->__toString() < $count) {
// Allow pre-commit to override the commit number (often branch number is higher than dev's)
if ($update) {
if (GIT_PRE_COMMIT === true) {
// only the pre-commit script is allowed to set the NEXT commit number
$count++;
}
if ($count !== $this->_vers->git->commit) {
echo ColorCLI::primary("Updating commit number to {$count}");
$this->_vers->git->commit = $count;
$this->_changes |= self::UPDATED_GIT_COMMIT;
}
}
return $this->_vers->git->commit;
}
return false;
}
/**
* Checks the git's latest version tag against the XML's stored value. Version should be
* Major.Minor.Revision[.fix] (**commit number is NOT revision**)
* @param boolean $update Whether the XML should be updated by the check.
* @return boolean The new git's latest version tag, or false.
*/
public function checkGitTag($update = true)
{
trigger_error(
'This method is deprecated. Use app/extensions/utils/Versions::checkGitTag() instead.'
);
$branch = $this->git->getBranch();
$this->_gitHighestTag = $latest = trim($this->git->tagLatest());
$ver = preg_match('#v(\d+\.\d+\.\d+).*#', $latest, $matches) ? $matches[1] : $latest;
if (!in_array($branch, $this->_stable, false)) {
if (version_compare($this->_vers->git->tag, '0.0.0', '!=')) {
$this->_vers->git->tag = '0.0.0';
$this->_changes |= self::UPDATED_GIT_TAG;
}
return $this->_vers->git->tag;
}
// Check if version file's entry is the same as current branch's tag
if (version_compare($this->_vers->git->tag, $latest, '!=')) {
if ($update) {
echo ColorCLI::primaryOver('Updating tag version to ') . ColorCLI::headerOver($latest);
$this->_vers->git->tag = $ver;
$this->_changes |= self::UPDATED_GIT_TAG;
} else {
echo ColorCLI::primaryOver('Leaving tag version at ') .
ColorCLI::headerOver($this->_vers->git->tag);
}
return $this->_vers->git->tag;
} else {
echo ColorCLI::primaryOver('Tag version is ') . ColorCLI::header($latest);
}
return false;
}
/**
* Checks the database sqlpatch setting against the XML's stored value.
*
* @param boolean $update Whether the XML should be updated by the check.
*
* @return boolean The new database sqlpatch version, or false.
*/
public function checkSQLDb($update = false): bool
{
$this->checkSQLFileLatest($update);
//$settings = new DB();
//$setting = $settings->getSetting('sqlpatch');
if ($this->_vers->sql->db->__toString() !== $this->_vers->sql->file->__toString()) {
if ($update) {
echo ColorCLI::primaryOver('Updating Db revision to ' . $this->_vers->sql->file);
$this->_vers->sql->db = $this->_vers->sql->file->__toString();
$this->_changes |= self::UPDATED_SQL_DB_PATCH;
}
return $this->_vers->patch->db;
}
return false;
}
/**
* Checks the numeric value from the last SQL patch file, updating the versions file if desired.
*
* @param bool $update Whether to update the versions file.
*
* @return bool|int False if there is a problem, otherwise the number from the last patch file.
*/
public function checkSQLFileLatest($update = true)
{
$options = [
'data' => NN_RES . 'db' . DS . 'schema' . DS . 'data' . DS,
'ext' => 'sql',
'path' => NN_RES . 'db' . DS . 'patches' . DS . 'mysql',
'regex' =>
'#^' . Utility::PATH_REGEX . '(?P<patch>\d{4})~(?P<table>\w+)\.sql$#',
'safe' => true,
];
$files = Utility::getDirFiles($options);
natsort($files);
$last = preg_match($options['regex'], end($files), $matches) ? (int)$matches['patch'] : false;
if ($update) {
if ($last !== false && $this->_vers->sql->file->__toString() !== $last) {
echo ColorCLI::primary('Updating latest patch file to ' . $last);
$this->_vers->sql->file = $last;
$this->_changes |= self::UPDATED_SQL_FILE_LAST;
}
if ($this->_vers->sql->file->__toString() !== $last) {
$this->_vers->sql->file = $last;
$this->_changes |= self::UPDATED_SQL_DB_PATCH;
}
}
return $last;
}
public function getCommit()
{
return $this->_vers->git->commit->__toString();
}
public function getGitHookPrecommit()
{
return $this->_vers->git->hooks->precommit->__toString();
}
public function getSQLPatchFromDb()
{
return $this->_vers->sql->db->__toString();
}
public function getSQLPatchFromFiles()
{
return $this->_vers->sql->file->__toString();
}
public function getTagVersion()
{
if (empty($this->_gitHighestTag)) {
$this->checkGitTag();
}
return $this->_gitHighestTag;
}
/**
* @param null|string $filepath
*
* @return object|\SimpleXMLElement
* @throws \Exception
*/
public function getValidVersionsFile($filepath = null)
{
$filepath = empty($filepath) ? $this->_filespec : $filepath;
$temp = libxml_use_internal_errors(true);
$this->_xml = simplexml_load_file($filepath);
libxml_use_internal_errors($temp);
if ($this->_xml === false) {
if (Utility::isCLI()) {
ColorCLI::error("Your versions XML file ($filepath) is broken, try updating from git.");
}
throw new \RuntimeException("Failed to open versions XML file '$filepath'");
}
if ($this->_xml->count() > 0) {
$vers = $this->_xml->xpath('/nntmux/versions');
if ($vers[0]->count() === 0) {
ColorCLI::error('Your versions XML file ({NN_VERSIONS}) does not contain version info, try updating from git.');
throw new \RuntimeException("Failed to find versions node in XML file '$filepath'");
} else {
ColorCLI::primary('Your versions XML file ({NN_VERSIONS}) looks okay, continuing.');
$this->_vers = &$this->_xml->versions;
}
} else {
throw new \RuntimeException("No elements in file!\n");
}
return $this->_xml;
}
/**
* Check whether the XML has been changed by one of the methods here.
* @return boolean True if the XML has been changed.
*/
public function hasChanged(): bool
{
return $this->_changes !== 0;
}
public function save(): void
{
if ($this->hasChanged()) {
$this->_xml->asXML($this->_filespec);
$this->_changes = 0;
}
}
}