From f800abeea4f6c68182c51cd4aaea19d7636431c8 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Wed, 9 Oct 2019 17:31:19 +0200 Subject: [minilinux] Rewrite for multiple version/sources handling * You can supply multiple sources for updates (URLs) * Sources can provide multiple branches * Each branch can supply multiple versions (eg. updates) TODO: Set global default version TODO: Supply hook to serversetup-ipxe to add specific boot entries TODO: UX polish TODO: phpdoc/polish --- inc/property.inc.php | 42 --- inc/taskmanager.inc.php | 16 ++ inc/taskmanagercallback.inc.php | 9 + modules-available/minilinux/hooks/cron.inc.php | 6 + .../minilinux/hooks/ipxe-bootentry.inc.php | 42 +++ modules-available/minilinux/inc/minilinux.inc.php | 228 ++++++++++++++++ modules-available/minilinux/install.inc.php | 40 +++ modules-available/minilinux/lang/de/messages.json | 5 +- modules-available/minilinux/lang/de/module.json | 6 +- .../minilinux/lang/de/template-tags.json | 29 +- modules-available/minilinux/lang/en/messages.json | 5 +- modules-available/minilinux/lang/en/module.json | 7 +- modules-available/minilinux/page.inc.php | 299 ++++++++++++++------- .../minilinux/permissions/permissions.json | 3 + .../minilinux/templates/branches.html | 73 +++++ .../minilinux/templates/download.html | 1 - .../minilinux/templates/filelist.html | 125 ++++----- .../minilinux/templates/page-minilinux.html | 26 +- modules-available/minilinux/templates/sources.html | 42 +++ .../minilinux/templates/versionlist.html | 39 +++ style/default.css | 2 +- 21 files changed, 790 insertions(+), 255 deletions(-) create mode 100644 modules-available/minilinux/hooks/cron.inc.php create mode 100644 modules-available/minilinux/hooks/ipxe-bootentry.inc.php create mode 100644 modules-available/minilinux/inc/minilinux.inc.php create mode 100644 modules-available/minilinux/install.inc.php create mode 100644 modules-available/minilinux/templates/branches.html delete mode 100644 modules-available/minilinux/templates/download.html create mode 100644 modules-available/minilinux/templates/sources.html create mode 100644 modules-available/minilinux/templates/versionlist.html diff --git a/inc/property.inc.php b/inc/property.inc.php index b69be1f8..3911b0d4 100644 --- a/inc/property.inc.php +++ b/inc/property.inc.php @@ -145,43 +145,6 @@ class Property self::set('ipxe-menu', json_encode($value)); } - public static function getVersionCheckTaskId() - { - return self::get('versioncheck-task'); - } - - public static function setVersionCheckTaskId($value) - { - self::set('versioncheck-task', $value); - } - - public static function getVersionCheckInformation() - { - $data = json_decode(self::get('versioncheck-data', '[]'), true); - if (isset($data['time']) && $data['time'] + 60 > time()) - return $data; - $task = Taskmanager::submit('DownloadText', array( - 'url' => CONFIG_REMOTE_ML . '/list.php' - )); - if (!isset($task['id'])) - return 'Could not start list download (' . Message::asString() . ')'; - if (!Taskmanager::isFinished($task)) { - $task = Taskmanager::waitComplete($task['id'], 5000); - } - if ($task['statusCode'] !== Taskmanager::TASK_FINISHED || !isset($task['data']['content'])) { - return isset($task['data']['error']) ? $task['data']['error'] : 'Timeout'; - } - $data = json_decode($task['data']['content'], true); - $data['time'] = time(); - self::setVersionCheckInformation($data); - return $data; - } - - public static function setVersionCheckInformation($value) - { - self::set('versioncheck-data', json_encode($value), 1); - } - public static function getVmStoreConfig() { return json_decode(self::get('vmstore-config'), true); @@ -251,9 +214,4 @@ class Property return self::get('password-type', 'password'); } - public static function getIpxeDefault() - { - return self::get('default-ipxe'); - } - } diff --git a/inc/taskmanager.inc.php b/inc/taskmanager.inc.php index 8fe70d00..547a75d4 100644 --- a/inc/taskmanager.inc.php +++ b/inc/taskmanager.inc.php @@ -175,6 +175,22 @@ class Taskmanager return false; } + /** + * Check whether the given task is running, that is either waiting for execution + * or currently executing. + * + * @param array $task struct representing task, obtained by ::status + * @return boolean true if task is waiting or executing, false if waiting for execution or currently executing, no valid task, etc. + */ + public static function isRunning($task) + { + if (!is_array($task) || !isset($task['statusCode']) || !isset($task['id'])) + return false; + if ($task['statusCode'] === Taskmanager::TASK_WAITING || $task['statusCode'] === Taskmanager::TASK_PROCESSING) + return true; + return false; + } + public static function addErrorMessage($task) { static $failure = false; diff --git a/inc/taskmanagercallback.inc.php b/inc/taskmanagercallback.inc.php index 8e253962..d1152bfd 100644 --- a/inc/taskmanagercallback.inc.php +++ b/inc/taskmanagercallback.inc.php @@ -184,6 +184,15 @@ class TaskmanagerCallback } } + public static function mlDownload($task, $args) + { + $mod = Module::get('minilinux'); + if ($mod === false) + return; + $mod->activate(1, false); + MiniLinux::listDownloadCallback($task, $args); + } + public static function uploadimg($task) { //$string=var_export($task, true); diff --git a/modules-available/minilinux/hooks/cron.inc.php b/modules-available/minilinux/hooks/cron.inc.php new file mode 100644 index 00000000..fa6e4c70 --- /dev/null +++ b/modules-available/minilinux/hooks/cron.inc.php @@ -0,0 +1,6 @@ +executable = 'mspaint.exe'; + $bios->initRd = 'www.google.de'; + $bios->commandLine = '-q'; + return BootEntry::newStandardBootEntry($bios, false, 'agnostic'); + } +} + +return new Wurst(); \ No newline at end of file diff --git a/modules-available/minilinux/inc/minilinux.inc.php b/modules-available/minilinux/inc/minilinux.inc.php new file mode 100644 index 00000000..46c63c94 --- /dev/null +++ b/modules-available/minilinux/inc/minilinux.inc.php @@ -0,0 +1,228 @@ + $stamp) + return 0; // In progress... + Property::set(self::PROPERTY_KEY_FETCHTIME, $stamp, 1); + Database::exec('LOCK TABLES callback WRITE, + minilinux_source WRITE, minilinux_branch WRITE, minilinux_version WRITE'); + Database::exec('UPDATE minilinux_source SET taskid = UUID()'); + $cutoff = time() - 3600; + Database::exec("UPDATE minilinux_version + INNER JOIN minilinux_branch USING (branchid) + INNER JOIN minilinux_source USING (sourceid) + SET orphan = orphan + 1 WHERE minilinux_source.lastupdate < $cutoff"); + $list = Database::queryAll('SELECT sourceid, url, taskid FROM minilinux_source'); + foreach ($list as $source) { + Taskmanager::submit('DownloadText', array( + 'id' => $source['taskid'], + 'url' => $source['url'], + ), true); + TaskmanagerCallback::addCallback($source['taskid'], 'mlDownload', $source['sourceid']); + } + Database::exec('UNLOCK TABLES'); + return count($list); + } + + public static function listDownloadCallback($task, $sourceid) + { + $taskId = $task['id']; + $data = json_decode($task['data']['content'], true); + if (!is_array($data)) { + EventLog::warning('Cannot download Linux version meta data for ' . $sourceid); + error_log(print_r($task, true)); + $lastupdate = 'lastupdate'; + } else { + if (isset($data['systems']) && is_array($data['systems'])) { + self::addBranches($sourceid, $data['systems']); + } + $lastupdate = 'UNIX_TIMESTAMP()'; + } + Database::exec("UPDATE minilinux_source SET lastupdate = $lastupdate, taskid = NULL + WHERE sourceid = :sourceid AND taskid = :taskid", + ['sourceid' => $sourceid, 'taskid' => $taskId]); + } + + private static function addBranches($sourceid, $systems) + { + foreach ($systems as $system) { + if (!self::isValidIdPart($system['id'])) + continue; + $branchid = $sourceid . '/' . $system['id']; + $title = empty($system['title']) ? $branchid : $system['title']; + $description = empty($system['description']) ? '' : $system['description']; + Database::exec('INSERT INTO minilinux_branch (branchid, sourceid, title, description) + VALUES (:branchid, :sourceid, :title, :description) + ON DUPLICATE KEY UPDATE title = VALUES(title), description = VALUES(description)', [ + 'branchid' => $branchid, + 'sourceid' => $sourceid, + 'title' => $title, + 'description' => $description, + ]); + if (isset($system['versions']) && is_array($system['versions'])) { + self::addVersions($branchid, $system['versions']); + } + } + } + + private static function addVersions($branchid, $versions) + { + foreach ($versions as $version) { + self::addVersion($branchid, $version); + } + } + + private static function addVersion($branchid, $version) + { + if (!self::isValidIdPart($version['version'])) { + error_log("Ignoring version {$version['version']} from $branchid: Invalid characters in ID"); + return; + } + if (empty($version['files']) && empty($version['cmdline'])) { + error_log("Ignoring version {$version['version']} from $branchid: Neither file list nor command line"); + return; + } + $versionid = $branchid . '/' . $version['version']; + $title = empty($version['title']) ? '' : $version['title']; + $dateline = empty($version['releasedate']) ? time() : (int)$version['releasedate']; + unset($version['version'], $version['title'], $version['releasedate']); + // Sanitize files array + if (!isset($version['files']) || !is_array($version['files'])) { + unset($version['files']); + } else { + foreach (array_keys($version['files']) as $key) { + $file =& $version['files'][$key]; + if (empty($file['name'])) { + error_log("Ignoring version {$version['version']} from $branchid: Entry in file list has missing file name"); + return; + } + if ($file['name'] === 'menu.txt' || $file['name'] === 'menu-debug.txt') { + unset($version['files'][$key]); + continue; + } + if (empty($file['gpg'])) { + error_log("Ignoring version {$version['version']} from $branchid: {$file['name']} has no GPG signature"); + return; + } + if (preg_match(',/\.\.|\.\./|/|\x00,', $file['name']) > 0) { // Invalid chars + error_log("Ignoring version {$version['version']} from $branchid: {$file['name']} contains invalid characters"); + return; + } + if (isset($file['md5'])) { + $file['md5'] = strtolower($file['md5']); + } + } + unset($file); + $version['files'] = array_values($version['files']); + } + $data = json_encode($version); + Database::exec('INSERT INTO minilinux_version (versionid, branchid, title, dateline, data, orphan) + VALUES (:versionid, :branchid, :title, :dateline, :data, 0) + ON DUPLICATE KEY UPDATE title = VALUES(title), data = VALUES(data), orphan = 0', [ + 'versionid' => $versionid, + 'branchid' => $branchid, + 'title' => $title, + 'dateline' => $dateline, + 'data' => $data, + ]); + } + + private static function isValidIdPart($str) + { + return preg_match('/^[a-z0-9_\-]+$/', $str) > 0; + } + + public static function validateDownloadTask($versionid, $taskid) + { + if ($taskid === null) + return false; + $task = Taskmanager::status($taskid); + if (Taskmanager::isTask($task) && !Taskmanager::isFailed($task) + && (is_dir(CONFIG_HTTP_DIR . '/' . $versionid) || !Taskmanager::isFinished($task))) + return $task['id']; + Database::exec('UPDATE minilinux_version SET taskid = NULL + WHERE versionid = :versionid AND taskid = :taskid', + ['versionid' => $versionid, 'taskid' => $taskid]); + return false; + } + + /** + * Download the files for the given version id + * @param $versionid + * @return bool + */ + public static function downloadVersion($versionid) + { + $ver = Database::queryFirst('SELECT s.url, s.pubkey, v.versionid, v.taskid, v.data FROM minilinux_version v + INNER JOIN minilinux_branch b USING (branchid) + INNER JOIN minilinux_source s USING (sourceid) + WHERE versionid = :versionid', + ['versionid' => $versionid]); + if ($ver === false) + return false; + $taskid = self::validateDownloadTask($versionid, $ver['taskid']); + if ($taskid !== false) + return $taskid; + $data = json_decode($ver['data'], true); + if (!is_array($data)) { + EventLog::warning("Cannot download Linux '$versionid': Corrupted meta data.", $ver['data']); + return false; + } + if (empty($data['files'])) + return false; + $list = []; + $legacyDir = preg_replace(',^[^/]*/,', '', $versionid); + foreach ($data['files'] as $file) { + if (empty($file['name'])) + continue; + $list[] = [ + 'id' => self::fileToId($versionid, $file['name']), + 'url' => empty($file['url']) + ? ($ver['url'] . '/' . $legacyDir . '/' . $file['name']) + : ($ver['url'] . '/' . $file['url']), + 'fileName' => $file['name'], + 'gpg' => $file['gpg'], + ]; + } + error_log(print_r($list, true)); + $uuid = Util::randomUuid(); + Database::exec('LOCK TABLES minilinux_version WRITE'); + $aff = Database::exec('UPDATE minilinux_version SET taskid = :taskid WHERE versionid = :versionid AND taskid IS NULL', + ['taskid' => $uuid, 'versionid' => $versionid]); + if ($aff > 0) { + $task = Taskmanager::submit('DownloadFiles', [ + 'id' => $uuid, + 'baseDir' => CONFIG_HTTP_DIR . '/' . $versionid, + 'gpgPubKey' => $ver['pubkey'], + 'files' => $list, + ]); + if (Taskmanager::isFailed($task)) { + error_log(print_r($task, true)); + $task = false; + } else { + $task = $task['id']; + } + } else { + $task = false; + } + Database::exec('UNLOCK TABLES'); + if ($aff === 0) + return self::downloadVersion($versionid); + return $task; + } + + public static function fileToId($versionid, $fileName) + { + return 'x' . substr(md5($fileName . $versionid), 0, 8); + } + +} \ No newline at end of file diff --git a/modules-available/minilinux/install.inc.php b/modules-available/minilinux/install.inc.php new file mode 100644 index 00000000..50be13a5 --- /dev/null +++ b/modules-available/minilinux/install.inc.php @@ -0,0 +1,40 @@ +deleteVersion(); + } elseif ($show === 'updatesources') { + $this->updateSources(); + } + Util::redirect('?do=minilinux'); + } + User::assertPermission('view'); } protected function doRender() { - Render::addTemplate('page-minilinux', array( - 'listurl' => '?do=MiniLinux&async=true&action=list' - )); + Render::addTemplate('page-minilinux'); + // List branches and versions + $branches = Database::queryAll('SELECT sourceid, branchid, title FROM minilinux_branch ORDER BY title ASC'); + $versions = $this->queryAllVersionsByBranch(); + foreach ($branches as &$branch) { + if (isset($versions[$branch['branchid']])) { + $branch['versionlist'] = $this->renderVersionList($versions[$branch['branchid']]); + } + } + Render::addTemplate('branches', ['branches' => $branches]); + // List sources + $res = Database::simpleQuery('SELECT sourceid, title, url, lastupdate, pubkey FROM minilinux_source ORDER BY title, sourceid'); + $data = ['list' => [], 'show_refresh' => true]; + $tooOld = strtotime('-7 days'); + $showRefresh = strtotime('-10 minutes'); + while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + $row['lastupdate_s'] = Util::prettyTime($row['lastupdate']); + if ($row['lastupdate'] != 0 && $row['lastupdate'] < $tooOld) { + $row['update_class'] = 'text-danger'; + } + if ($row['lastupdate'] > $showRefresh) { + $data['show_refresh'] = false; + } + $data['list'][] = $row; + } + Render::addTemplate('sources', $data); } protected function doAjax() { - $data = Property::getVersionCheckInformation(); - if (!is_array($data) || !isset($data['systems'])) { - echo Render::parse('messagebox', array( - 'type' => 'danger', - 'message' => 'Failed to retrieve the list: ' . print_r($data, true) - ), 'main'); - return; + User::load(); + $show = Request::post('show', false, 'string'); + if ($show === 'version') { + $this->ajaxVersion(); + } elseif ($show === 'download') { + $this->ajaxDownload(); } - $action = Request::any('action'); - $selectedVersion = (int)Request::any('version', 0); - switch ($action) { - case 'list': - $count = 0; - foreach ($data['systems'] as &$system) { - // Get latest version, build simple array of all version numbers - $versionNumbers = array(); - $selected = false; - foreach ($system['versions'] as $version) { - if (!is_numeric($version['version']) || $version['version'] < 1) - continue; - if ($selectedVersion === 0 && ($selected === false || $selected['version'] < $version['version'])) - $selected = $version; - elseif ($version['version'] == $selectedVersion) - $selected = $version; - $versionNumbers[(int)$version['version']] = array( - 'version' => $version['version'] - ); + } + + private function queryAllVersionsByBranch() + { + $list = []; + $res = Database::simpleQuery('SELECT branchid, versionid, title, dateline, orphan, taskid + FROM minilinux_version ORDER BY branchid, dateline, versionid'); + while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + $list[$row['branchid']][] = $row; + } + return $list; + } + + private function renderVersionList($versions) + { + foreach ($versions as &$version) { + $version['dateline_s'] = Util::prettyTime($version['dateline']); + $version['orphan'] = ($version['orphan'] > 5); + $version['installed'] = is_dir(CONFIG_HTTP_DIR . '/' . $version['versionid']); + $version['downloading'] = $version['taskid'] && Taskmanager::isRunning(Taskmanager::status($version['taskid'])); + } + return Render::parse('versionlist', ['versions' => $versions]); + } + + private function ajaxVersion() + { + User::assertPermission('view'); + $verify = Request::post('verify', false, 'bool'); + $versionid = Request::post('version', false, 'string'); + if ($versionid === false) { + die('What!'); + } + $ver = Database::queryFirst('SELECT versionid, taskid, data FROM minilinux_version WHERE versionid = :versionid', + ['versionid' => $versionid]); + if ($ver === false) { + die('No such version'); + } + $versionid = $ver['versionid']; // Just to be sure -- should be safe for building a path either way + $data = json_decode($ver['data'], true); + if (!is_array($data)) { + die('Corrupted data'); + } + $data['versionid'] = $versionid; + $data['dltask'] = MiniLinux::validateDownloadTask($versionid, $ver['taskid']); + $data['verify_button'] = !$verify && $data['dltask'] === false; + if (is_array($data['files'])) { + $sort = []; + foreach ($data['files'] as &$file) { + if (empty($file['name'])) { + $sort[] = 'zzz' . implode(',', $file); + continue; } - if ($selected === false) continue; // No versions for this system!? - ksort($versionNumbers); - // Mark latest version as selected - $versionNumbers[(int)$selected['version']]['selected'] = true; - // Add status information to system and its files - foreach ($selected['files'] as &$file) { - $file['uid'] = 'dlid' . $count++; - $local = CONFIG_HTTP_DIR . '/' . $system['id'] . '/' . $file['name']; - if (!file_exists($local) || filesize($local) !== $file['size'] || filemtime($local) < $file['mtime'] - || md5_file($local) !== $file['md5']) { - $file['fileChanged'] = true; - $system['systemChanged'] = true; - } - $taskId = Property::getDownloadTask($file['md5']); - if ($taskId !== false) { - $task = Taskmanager::status($taskId); - if (isset($task['data']['progress'])) { - $file['download'] = Render::parse('download', array( - 'task' => $taskId, - 'name' => $file['name'] - )); - } - } + $sort[] = $file['name']; + $s = $this->getFileState($versionid, $file, $verify); + if ($s !== self::FILE_OK) { + $data['verify_button'] = false; + $data['download_button'] = !$data['dltask']; } - unset($system['versions']); - $system['files'] = $selected['files']; - $system['version'] = $selected['version']; - } - $data['versions'] = array_values($versionNumbers); - Permission::addGlobalTags($data['perms'], null, ['update']); - echo Render::parse('filelist', $data); - return; - case 'download': - User::assertPermission('update'); - $id = Request::post('id'); - $name = Request::post('name'); - if (!$id || !$name || strpos("$id$name", '/') !== false) { - echo "Invalid download request"; - return; - } - $file = false; - $gpg = 'missing'; - foreach ($data['systems'] as &$system) { - if ($system['id'] !== $id) continue; - foreach ($system['versions'] as &$version) { - if ($version['version'] != $selectedVersion) continue; - foreach ($version['files'] as &$f) { - if ($f['name'] !== $name) continue; - $file = $f; - if (!empty($f['gpg'])) $gpg = $f['gpg']; - break; - } + if ($s !== self::FILE_MISSING) { + $data['delete_button'] = true; + } + $file['state'] = $this->fileStateToString($s); + if (isset($file['size'])) { + $file['size_s'] = Util::readableFileSize($file['size']); + } + if (isset($file['mtime'])) { + $file['mtime_s'] = Util::prettyTime($file['mtime']); + } + if ($data['dltask']) { + $file['fileid'] = MiniLinux::fileToId($versionid, $file['name']); } } - if ($file === false) { - echo "Nonexistent system/file: $id / $name"; - return; - } - $task = Taskmanager::submit('DownloadFile', array( - 'url' => CONFIG_REMOTE_ML . '/' . $id . '/' . $selectedVersion . '/' . $name, - 'destination' => CONFIG_HTTP_DIR . '/' . $id . '/' . $name, - 'gpg' => $gpg - )); - if (!isset($task['id'])) { - echo 'Error launching download task: ' . $task['statusCode']; - return; + unset($file); + array_multisort($sort, SORT_ASC, $data['files']); + } + echo Render::parse('filelist', $data); + } + + const FILE_OK = 0; + const FILE_MISSING = 1; + const FILE_SIZE_MISMATCH = 2; + const FILE_CHECKSUM_BAD = 3; + + private function getFileState($versionid, $file, $verify) + { + $path = CONFIG_HTTP_DIR . '/' . $versionid . '/' . $file['name']; + if (!is_file($path)) + return self::FILE_MISSING; + if (isset($file['size']) && filesize($path) != $file['size']) + return self::FILE_SIZE_MISMATCH; + if ($verify) { + // TODO: Others + if (isset($file['md5'])) { + if (md5_file($path) !== $file['md5']) + return self::FILE_CHECKSUM_BAD; } - Property::setDownloadTask($file['md5'], $task['id']); - echo Render::parse('download', array( - 'name' => $name, - 'task' => $task['id'] - )); + } + return self::FILE_OK; + } + + private function fileStateToString($state) + { + switch ($state) { + case self::FILE_CHECKSUM_BAD: + return Dictionary::translate('file-checksum-bad', true); + case self::FILE_SIZE_MISMATCH: + return Dictionary::translate('file-size-mismatch', true); + case self::FILE_MISSING: + return Dictionary::translate('file-missing', true); + case self::FILE_OK: + return Dictionary::translate('file-ok', true); + } + return '???'; + } + + private function ajaxDownload() + { + User::assertPermission('update'); + $version = Request::post('version', false, 'string'); + if ($version === false) { + die('No version'); + } + $task = MiniLinux::downloadVersion($version); + if ($task === false) { + Message::addError('no-such-version', $version); + Message::renderList(); + } else { + $this->ajaxVersion(); + } + } + + private function deleteVersion() + { + User::assertPermission('delete'); + $versionid = Request::post('version', false, 'string'); + if ($versionid === false) { + Message::addError('main.parameter-missing', 'versionid'); + return; + } + $version = Database::queryFirst('SELECT versionid FROM minilinux_version WHERE versionid = :versionid', + ['versionid' => $versionid]); + if ($version === false) { + Message::addError('no-such-version'); return; } + $path = CONFIG_HTTP_DIR . '/' . $version['versionid']; + $task = Taskmanager::submit('DeleteDirectory', [ + 'path' => $path, + 'recursive' => true, + ]); + if ($task !== false) { + $task = Taskmanager::waitComplete($task, 2500); + if (Taskmanager::isFailed($task)) { + Message::addError('delete-error', $versionid, $task['data']['error']); + } else { + Message::addSuccess('version-deleted', $versionid); + } + } + } + + private function updateSources() + { + $ret = MiniLinux::updateList(); + if ($ret > 0) { + sleep(2); + Trigger::checkCallbacks(); + } } } diff --git a/modules-available/minilinux/permissions/permissions.json b/modules-available/minilinux/permissions/permissions.json index b018ee72..ec311047 100644 --- a/modules-available/minilinux/permissions/permissions.json +++ b/modules-available/minilinux/permissions/permissions.json @@ -4,5 +4,8 @@ }, "update": { "location-aware": false + }, + "delete": { + "location-aware": false } } \ No newline at end of file diff --git a/modules-available/minilinux/templates/branches.html b/modules-available/minilinux/templates/branches.html new file mode 100644 index 00000000..1ba9497c --- /dev/null +++ b/modules-available/minilinux/templates/branches.html @@ -0,0 +1,73 @@ +{{#branches}} +
+
+
+ {{sourceid}} {{branchid}} +
+ {{title}} +
+
+ +
+ {{{versionlist}}} +
+{{/branches}} + \ No newline at end of file diff --git a/modules-available/minilinux/templates/download.html b/modules-available/minilinux/templates/download.html deleted file mode 100644 index 2e32df5a..00000000 --- a/modules-available/minilinux/templates/download.html +++ /dev/null @@ -1 +0,0 @@ -
{{name}}
\ No newline at end of file diff --git a/modules-available/minilinux/templates/filelist.html b/modules-available/minilinux/templates/filelist.html index 234b6c41..2c26edf9 100644 --- a/modules-available/minilinux/templates/filelist.html +++ b/modules-available/minilinux/templates/filelist.html @@ -1,74 +1,53 @@ - {{#systems}} -

{{title}}

-
-
- {{lang_desiredVersion}} - +
+
+ + + {{#verify_button}} + + {{/verify_button}} + {{#download_button}} + + {{/download_button}} + {{#delete_button}} + + {{/delete_button}} +
+
+
+ +{{#files}} + + + + + + + +{{/files}} +
 {{name}}{{size_s}}{{mtime_s}} + {{^dltask}} + {{state}} + {{/dltask}} + {{#dltask}} +
+
+
+
- {{#systemChanged}} -

- {{lang_canUpdate1}} {{title}} {{lang_canUpdate2}} -

- - {{/systemChanged}} - {{^systemChanged}} -

{{lang_systemUpdated}}

- {{/systemChanged}} -
-

{{lang_filesInVersion}} {{version}}

-
    - {{#files}} -
  • -
    -
    {{name}}
    -
    - {{^fileChanged}} {{lang_uptodate}}{{/fileChanged}} - {{#fileChanged}} {{lang_outdated}}{{/fileChanged}} -
    -
    - {{#fileChanged}} {{/fileChanged}} - {{^fileChanged}} {{/fileChanged}} -
    -
    - {{{download}}} -
  • - {{/files}} -
- - - {{/systems}} - {{^systems}} -
{{lang_configurationPackageNotFound}}
- {{/systems}} - - + {{/dltask}} +
+{{#dltask}} + +{{/dltask}} +
\ No newline at end of file diff --git a/modules-available/minilinux/templates/page-minilinux.html b/modules-available/minilinux/templates/page-minilinux.html index afccf230..2cbde608 100644 --- a/modules-available/minilinux/templates/page-minilinux.html +++ b/modules-available/minilinux/templates/page-minilinux.html @@ -1,25 +1,3 @@ -
-
{{lang_listObtained}}
-
+

{{lang_minilinuxHeading}}

- \ No newline at end of file +

{{lang_introText}}

\ No newline at end of file diff --git a/modules-available/minilinux/templates/sources.html b/modules-available/minilinux/templates/sources.html new file mode 100644 index 00000000..f2e54745 --- /dev/null +++ b/modules-available/minilinux/templates/sources.html @@ -0,0 +1,42 @@ +
+
+ {{lang_sources}} +
+ + + + + + + + + + + + {{#list}} + + + + + + + + {{/list}} + +
{{lang_id}}{{lang_title}}{{lang_url}}{{lang_lastUpdate}}{{lang_key}}
{{sourceid}}{{title}}{{url}}{{lastupdate_s}} + + +
+
+
+ + +
+
+
\ No newline at end of file diff --git a/modules-available/minilinux/templates/versionlist.html b/modules-available/minilinux/templates/versionlist.html new file mode 100644 index 00000000..1e5c7c96 --- /dev/null +++ b/modules-available/minilinux/templates/versionlist.html @@ -0,0 +1,39 @@ + + + + + + + + +{{#versions}} + + + + + + + + + + +{{/versions}} +
{{lang_version}}{{lang_releaseDate}}{{lang_title}}
+ + {{versionid}} + + + {{dateline_s}}{{title}} + {{^installed}} + {{^downloading}} + + {{/downloading}} + {{/installed}} + + {{#orphan}} + {{lang_orphanedVersion}} + {{/orphan}} +
\ No newline at end of file diff --git a/style/default.css b/style/default.css index 6c2beb86..e00037ab 100644 --- a/style/default.css +++ b/style/default.css @@ -76,7 +76,7 @@ body { } .slx-table td { - padding-right: 7px; + padding-right: 9px; padding-bottom: 2px; } -- cgit v1.2.3-55-g7522