<?php declare (strict_types=1); use Airship\Engine\State; /** * This script runs when upgrading to v1.3.0 from an earlier version. * It deletes the old symlinks used for resolving Motif templates. * The bootstrapping process is sufficient to restore them. */ $state = State::instance(); foreach ($state->cabins as $cabin) { $cabinName = (string) ($cabin['namespace'] ?? $cabin['name']); foreach (\glob(ROOT . '/Cabin/' . $cabinName . '/Lens/motif/*') as $f) { $endPiece = \Airship\path_to_filename($f); if (\is_link($f)) { \unlink($f); } } }
/** * Remove a motif * * @param array $info * @return string */ protected function removeMotif(array $info) : string { $ret = ''; foreach (\glob(ROOT . '/Cabin/*') as $cabinDir) { if (!\is_dir($cabinDir)) { continue; } $cabin = \Airship\path_to_filename($cabinDir); // The cache file has a combined $pathInfo = $this->getMotifPath($cabin, $info); if (empty($pathInfo)) { continue; } $ret .= "\tRemoving motif from {$cabin}.\n"; list($key, $path) = $pathInfo; $this->deleteMotifFromCabin($cabin, $key); if (\is_dir(ROOT . '/Motifs/' . $path)) { $ret .= \shell_exec('rm -rf ' . \escapeshellarg(ROOT . '/Motifs/' . $path)); \clearstatcache(); } if (\is_link(ROOT . '/Cabin/' . $cabin . '/Lens/motif/' . $key)) { \unlink(ROOT . '/Cabin/' . $cabin . '/Lens/motif/' . $key); } } return $ret; }
<?php declare (strict_types=1); use Airship\Engine\Gears; /** * Let's gearify the current cabin: * * e.g. Landing__IndexPage => \Airship\Cabin\Hull\Landing\IndexPage * */ $cabinGearsClosure = function () { foreach (['Landing', 'Blueprint'] as $dir) { foreach (\glob(CABIN_DIR . '/' . $dir . '/*.php') as $landing) { $filename = \Airship\path_to_filename($landing, true); if ($filename === 'init_gear') { continue; } Gears::lazyForge($dir . '__' . $filename, '\\Airship\\Cabin\\' . CABIN_NAME . '\\' . $dir . '\\' . $filename); } } }; $cabinGearsClosure(); unset($cabinGearsClosure);
/** * @covers \Airship\tempnam() */ public function testTempNam() { $name = \Airship\tempnam(); $name2 = \Airship\tempnam('foo-'); $name3 = \Airship\tempnam('foo-', 'txt'); $this->assertFileNotExists($name); $this->assertFileNotExists($name2); $this->assertFileNotExists($name3); $this->assertSame('foo-', Binary::safeSubstr(\Airship\path_to_filename($name3), 0, 4)); $this->assertSame('.txt', Binary::safeSubstr($name3, -4)); }
// Editor templates. if (!\is_link(ROOT . '/Installer/skins/cabin_links/' . $name)) { if (\is_dir(ROOT . '/Installer/skins/cabin_links/' . $name)) { \rmdir(ROOT . '/Installer/skins/cabin_links/' . $name); } elseif (\file_exists(ROOT . '/Installer/skins/cabin_links/' . $name)) { \unlink(ROOT . '/Installer/skins/cabin_links/' . $name); } \symlink(ROOT . '/Cabin/' . $name . '/config/editor_templates', ROOT . '/Installer/skins/cabin_links/' . $name); } // Any Motifs we ship with are suitable for all of the Cabins we ship with. // Less configuration headaches. foreach (\glob(ROOT . '/Motifs/*') as $motifDir) { if (\is_dir($motifDir)) { $supplier = \Airship\path_to_filename($motifDir); foreach (\glob($motifDir . '/*') as $sub) { $motif = \Airship\path_to_filename($sub); $linkFrom = $dir . '/public/motif/' . $motif; $n = 1; while (\is_link($linkFrom)) { if (\realpath($linkFrom) !== \realpath($sub)) { ++$n; $linkFrom = $dir . '/public/motif/' . $motif . '-' . $n; } else { break; } } \symlink($sub . '/public', $linkFrom); } } } }
/** * @route admin/settings */ public function manageSettings() { $state = State::instance(); $settings = ['universal' => $state->universal]; $post = $this->post(new SettingsFilter()); if (!empty($post)) { if ($this->saveSettings($post)) { \Airship\clear_cache(); \Airship\redirect($this->airship_cabin_prefix . '/admin/settings', ['msg' => 'saved']); } else { $this->log('Could not save new settings', LogLevel::ALERT); } } // Load individual files... $settings['cabins'] = $this->loadJSONConfigFile('cabins.json'); $settings['content_security_policy'] = $this->loadJSONConfigFile('content_security_policy.json'); $settings['keyring'] = $this->loadJSONConfigFile('keyring.json'); foreach (\Airship\list_all_files(ROOT . '/config/supplier_keys/', 'json') as $supplier) { $name = \Airship\path_to_filename($supplier, true); $settings['suppliers'][$name] = \Airship\loadJSON($supplier); } $this->lens('admin_settings', ['active_link' => 'bridge-link-admin-settings', 'config' => $settings, 'groups' => $this->acct->getGroupTree()]); }
/** * Motif install process. * * 1. Extract files to the appropriate directory. * 2. If this is a cabin-specific motif, update motifs.json. * Otherwise, it's a global Motif. Enable for all cabins. * 3. Create symbolic links. * 4. Clear cache files. * * @param InstallFile $fileInfo * @return bool */ public function install(InstallFile $fileInfo) : bool { $path = $fileInfo->getPath(); $zip = new \ZipArchive(); $res = $zip->open($path); if ($res !== true) { $this->log('Could not open the ZipArchive.', LogLevel::ERROR); return false; } // Extraction destination directory $dir = \implode(DIRECTORY_SEPARATOR, [ROOT, 'Motifs', $this->supplier->getName(), $this->package]); if (!\is_dir($dir)) { \mkdir($dir, 0775, true); } // Grab metadata $metadata = \Airship\parseJSON($zip->getArchiveComment(\ZipArchive::FL_UNCHANGED), true); if (isset($metadata['cabin'])) { $cabin = $this->expandCabinName($metadata['cabin']); if (!\is_dir(ROOT . '/Cabin/' . $cabin)) { $this->log('Could not install; cabin "' . $cabin . '" is not installed.', LogLevel::ERROR); return false; } } else { $cabin = null; } // Extract the new files to the current directory if (!$zip->extractTo($dir)) { $this->log('Could not extract Motif to its destination.', LogLevel::ERROR); return false; } // Add to the relevant motifs.json files if ($cabin) { $this->addMotifToCabin($cabin); } else { foreach (\glob(ROOT . '/Cabin/') as $cabin) { if (\is_dir($cabin)) { $this->addMotifToCabin(\Airship\path_to_filename($cabin)); } } } self::$continuumLogger->store(LogLevel::INFO, 'Motif install successful', $this->getLogContext($fileInfo)); // Finally, nuke the cache: return $this->clearCache(); }