137 lines
No EOL
3.6 KiB
PHP
137 lines
No EOL
3.6 KiB
PHP
<?php
|
|
|
|
namespace KD2;
|
|
|
|
class Fossil
|
|
{
|
|
/**
|
|
* Length for SHA1
|
|
*/
|
|
const HNAME_MIN = 40;
|
|
|
|
protected $db;
|
|
protected $url;
|
|
|
|
public function __construct($repo_file, $url)
|
|
{
|
|
$this->db = new DB_SQLite3($repo_file, SQLITE3_OPEN_READONLY);
|
|
$this->db->createFunction('repo_url', [$this, 'getURL']);
|
|
$this->url = $url;
|
|
}
|
|
|
|
public function getURL($uri = '')
|
|
{
|
|
return $this->url . $uri;
|
|
}
|
|
|
|
public function listUnversioned()
|
|
{
|
|
return $this->db->getGrouped('SELECT uvid, name, sz AS size, mtime, hash, repo_url(\'uv/\' || name) AS url
|
|
FROM unversioned WHERE hash IS NOT NULL ORDER BY mtime DESC;');
|
|
}
|
|
|
|
public function getTicketsStatus()
|
|
{
|
|
return $this->db->get('SELECT DISTINCT status FROM ticket;');
|
|
}
|
|
|
|
public function getTicketsTypes()
|
|
{
|
|
return $this->db->get('SELECT DISTINCT type FROM ticket;');
|
|
}
|
|
|
|
public function listTickets(array $filters = [])
|
|
{
|
|
$query = 'SELECT *, repo_url(\'tktview?name=\' || substr(tkt_uuid, 1, 10)) AS url FROM ticket WHERE 1';
|
|
$args = [];
|
|
|
|
foreach ($filters as $field => $value)
|
|
{
|
|
$query .= ' AND ' . $field . ' = ?';
|
|
$args[] = $value;
|
|
}
|
|
|
|
$query .= ' ORDER BY tkt_mtime DESC;';
|
|
|
|
return $this->db->get($query, $args);
|
|
}
|
|
|
|
public function bundlePreview($file, $force = false)
|
|
{
|
|
if (!is_readable($file))
|
|
{
|
|
throw new \RuntimeException('Cannot read file: ' . $file);
|
|
}
|
|
|
|
try {
|
|
$this->db->preparedQuery('ATTACH ? AS b1;', [$file]);
|
|
$a = $this->db->prepare('SELECT bcname, bcvalue FROM b1.bconfig LIMIT 1;');
|
|
$b = $this->db->prepare('SELECT blobid, uuid, sz, delta, notes, data FROM b1.bblob;');
|
|
|
|
if (!$a || !$b)
|
|
{
|
|
return false;
|
|
}
|
|
} catch (\Exception $e) {
|
|
$this->db->exec('DETACH b1;');
|
|
throw new \RuntimeException('Not a valid bundle file: ' . $e->getMessage(), 0, $e);
|
|
}
|
|
|
|
/* Only import a bundle that was generated from a repo with the same
|
|
** project code, unless the --force flag is true */
|
|
|
|
if (!$force)
|
|
{
|
|
$exists = $this->db->firstColumn('SELECT 1 FROM config, bconfig
|
|
WHERE config.name = \'project-code\'
|
|
AND bconfig.bcname = \'project-code\'
|
|
AND config.value = bconfig.bcvalue;');
|
|
|
|
if (!$exists)
|
|
{
|
|
$this->db->exec('DETACH b1;');
|
|
throw new \RuntimeException('project-code in the bundle does not match the repository project code.');
|
|
}
|
|
}
|
|
|
|
/* If the bundle contains deltas with a basis that is external to the
|
|
** bundle and those external basis files are missing from the local
|
|
** repo, then the delta encodings cannot be decoded and the bundle cannot
|
|
** be extracted. */
|
|
$missing_deltas = $this->db->firstColumn('SELECT group_concat(substr(delta,1,10), \' \') FROM bblob WHERE typeof(delta) = \'text\' AND length(delta) >= ? AND NOT EXISTS(SELECT 1 FROM blob WHERE uuid = bblob.delta)', self::HNAME_MIN);
|
|
|
|
if ($missing_deltas)
|
|
{
|
|
$this->db->exec('DETACH b1;');
|
|
throw new \RuntimeException('delta basis artifacts not found in repository: ' . $missing_deltas);
|
|
}
|
|
|
|
$this->db->begin();
|
|
|
|
$this->db->exec('CREATE TEMP TABLE bix(
|
|
blobid INTEGER PRIMARY KEY,
|
|
delta INTEGER
|
|
);
|
|
CREATE INDEX bixdelta ON bix(delta);
|
|
INSERT INTO bix(blobid,delta)
|
|
SELECT blobid,
|
|
CASE WHEN typeof(delta)==\'integer\'
|
|
THEN delta ELSE 0 END
|
|
FROM bblob
|
|
WHERE NOT EXISTS(SELECT 1 FROM blob WHERE uuid=bblob.uuid AND size>=0);
|
|
CREATE TEMP TABLE got(rid INTEGER PRIMARY KEY ON CONFLICT IGNORE);');
|
|
|
|
/*
|
|
manifest_crosslink_begin();
|
|
bundle_import_elements(0, 0, isPriv);
|
|
manifest_crosslink_end(0);
|
|
describe_artifacts_to_stdout("IN got", "Imported content:");
|
|
*/
|
|
|
|
$this->db->commit();
|
|
|
|
// gzuncompress on each delta
|
|
|
|
$this->db->exec('DETACH b1;');
|
|
}
|
|
} |