123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442 |
- <?php
- /**
- * @file
- * Drush hooks and include commands for Basic theme.
- */
- /**
- * Implements hook_drush_command().
- */
- function basic_drush_command() {
- $items['basic-install'] = array(
- 'description' => dt('Run through the installation process of the Basic theme.'),
- 'options' => array(
- 'destination' => array(
- 'description' => 'Path to which the theme will be placed. If you\'re providing a relative path, note it is relative to the drupal root.',
- 'example-value' => 'themes/',
- ),
- ),
- 'aliases' => array('binstall'),
- );
- return $items;
- }
- /**
- * Implements hook_drush_help().
- */
- function basic_drush_help($section) {
- switch ($section) {
- case 'drush:basic-install':
- return dt('Runs through an automated process for installing and renaming your theme to use as your own.');
- }
- }
- /**
- * Implements drush_hook_COMMAND().
- */
- function drush_basic_install() {
- drush_print('Checking for npm...');
- $npm_check_output = drush_shell_exec('npm version 2>&1');
- if (strpos($npm_check_output, 'command not found')) {
- drush_print('NPM could not be found. Please install npm (https://nodejs.org/en/) and try again.');
- exit();
- }
- else {
- drush_print('npm was found.');
- }
- // Prompt the user what we're doing.
- drush_print('-----------------------------');
- drush_print(dt('Welcome to the Basic Install!'));
- drush_print('-----------------------------');
- drush_print(dt('We will perform the automated tasks for you to use your new theme. We will create a copy of the Basic theme and store it in the standard theme directory or in spescified destination.'));
- drush_confirm(dt('Do you wish to continue?'));
- // Rebuild the theme data so that we can safely check for the existence of
- // themes by using the information provided by list_themes().
- $theme_handler = \Drupal::service('theme_handler');
- $theme_handler->rebuildThemeData();
- // Prompt for a theme name.
- $name = drush_prompt(dt('Please enter the name of that you want for your theme'), 'My Theme');
- // Try to generate a machine-readable name. If that fails, prompt for one.
- if (!$machine_name = drush_basic_generate_theme_name($name)) {
- drush_print(dt("Sorry, I couldn't generate a machine-readable name for @name", array(
- '@name' => $name,
- )));
- }
- // Prompt for a theme name using the automatically generated default if any.
- drush_set_option('machine-name', drush_basic_require_valid_theme_name(dt('Please enter a machine-readable name for your new theme'), $machine_name));
- // Try to generate a machine-readable name. If that fails, prompt for one.
- if (!$machine_name = drush_get_option('machine-name', drush_basic_generate_theme_name($name))) {
- drush_print(dt("Sorry, I couldn't generate a machine-readable name for @name. Please use the '--machine-name' option to specify it manually.", array(
- '@name' => $name,
- )));
- }
- $origin_path = $theme_handler->getTheme('basic')->getPath();
- $temporary = \Drupal::config('system.file')->get('path.temporary');
- $temp_path = $temporary . '/' . $machine_name;
- $destination_path = drush_basic_get_destination($machine_name);
- // Check whether the destination path exist and bail out if it does,
- // so we don't delete any important data by accident.
- if (file_exists($destination_path)) {
- return drush_set_error('BASIC_COPY_PATH', dt('The path !path already exists.', array(
- '!path' => $destination_path,
- )));
- }
- if (is_dir($temp_path)) {
- basic_rm_dir($temp_path);
- }
- // Copy into temp directory.
- if (!basic_copy_dir($origin_path, $temp_path)) {
- return drush_set_error('DRUSH_COPY_DIR_FAILURE', dt('Failed to copy !origin_path to !temp_path.', array(
- '!origin_path' => $origin_path,
- '!temp_path' => $temp_path,
- )));
- }
- // Recursively rewrite the file names and contents of all the files that are
- // now in the subtheme's directory to represent the human- and
- // machine-readable names of the subtheme.
- $search = array(
- 'basic' => $machine_name,
- 'Basic' => $name,
- );
- if (!drush_basic_rewrite_recursive($temp_path, array_keys($search), array_values($search))) {
- return drush_set_error('BASIC_COPY_GENERATE_THEME', dt('Failed to rewrite files and contents while generating theme.'));
- }
- // Copy from temp folder into new theme's folder.
- if (!basic_copy_dir($temp_path, $destination_path)) {
- return drush_set_error('DRUSH_COPY_DIR_FAILURE', dt('Failed to copy !temp_path to !destination_path.', array(
- '!temp_path' => $temp_path,
- '!destination_path' => $destination_path,
- )));
- }
- // Run npm install on the new theme folder.
- drush_print(dt("Building node dependencies for the theme @theme. This could take a couple minutes.", array(
- '@theme' => $machine_name,
- )));
- drush_op('chdir', DRUPAL_ROOT . '/' . $destination_path);
- drush_shell_exec('npm install');
- drush_print(dt("Node dependancies have been successfully built."));
- // Notify user of successful installation.
- drush_print(dt("------------------------------------------------------------------"));
- drush_print(dt("The new theme, !theme, has been successfully derived from Basic and placed in !destination.", array(
- '!theme' => $machine_name,
- '!destination' => $destination_path,
- )));
- drush_print(dt("------------------------------------------------------------------"));
- }
- /**
- * Generates a valid machine-readable name for a theme from any string.
- *
- * @param string $string
- * The string to generate the machine-readable name from.
- *
- * @return string
- * The generated machine-readable name.
- */
- function drush_basic_generate_theme_name($string) {
- // Lowercase to start.
- $string = strtolower($string);
- // Machine-readable names have to start with a lowercase letter.
- // $string = preg_replace('/^[^a-z]+/', '', strtolower($string));
- // Machine-readable names may only contain alphanumeric characters and
- // underscores.
- $string = preg_replace('/[^a-z0-9_]+/', '_', $string);
- // Trim all trailing and leading underscores.
- $string = trim($string, '_');
- // Get list of current themes.
- $theme_handler = \Drupal::service('theme_handler');
- $themes = $theme_handler->listInfo();
- if (isset($themes[$string])) {
- $plain = $string;
- $counter = 0;
- while (isset($themes[$string])) {
- // Make sure that the machine-readable name of the theme is unique.
- $string = $plain . '_' . $counter++;
- }
- }
- return $string;
- }
- /**
- * Helper function that continuously prompts for a valid machine-readable name.
- *
- * @param string $message
- * The message that should be displayed.
- * @param string $default
- * (Optional) The default theme name. Defaults to NULL.
- *
- * @return string
- * A valid, unique machine-readable name.
- */
- function drush_basic_require_valid_theme_name($message, $default = NULL) {
- while (TRUE) {
- // Keep prompting for a machine-name until we get an acceptable value.
- $prompt = drush_prompt($message, $default);
- if (!preg_match('/^[a-z][a-z0-9_]*$/', $prompt)) {
- drush_print('The machine-readable name is invalid. It may only contain lowercase numbers, letters and underscores and must start with a letter.');
- }
- else {
- // Get list of current themes.
- $theme_handler = \Drupal::service('theme_handler');
- $themes = $theme_handler->listInfo();
- // Validate that the machine-readable name of the theme is unique.
- if (isset($themes[$prompt])) {
- drush_print(dt('A theme with the name @name already exists. The machine-readable name must be unique.', array(
- '@name' => $prompt,
- )));
- }
- else {
- // The given machine-readable name is valid. Let's proceed.
- return $prompt;
- }
- }
- }
- }
- /**
- * Helper function to get proper destination for the new theme.
- *
- * @param string $machine_name
- * A valid, unique machine-readable name for the new theme.
- *
- * @return string
- * The path to the destination where the new theme should be placed.
- */
- function drush_basic_get_destination($machine_name) {
- // Find proper destination if no destination option is provided.
- if ($destination = drush_get_option('destination')) {
- $destination_path = drush_trim_path($destination) . '/' . $machine_name;
- }
- else {
- $site_root = drush_get_context('DRUSH_DRUPAL_SITE_ROOT');
- if ($site_root == 'sites/default') {
- $destination_path = 'themes/' . $machine_name;
- }
- else {
- $destination_path = $site_root . '/themes/' . $machine_name;
- }
- }
- $destination_path = drush_normalize_path($destination_path);
- return $destination_path;
- }
- /**
- * Recursively rewrites (and renames) all files in a given path.
- *
- * @param string $path
- * The path to rewrite all files in.
- * @param string|array $search
- * The string(s) to look for when replacing the file names and contents. Can
- * be an array or a string.
- * @param string|array $replace
- * The string(s) to replace $search with. Can be an array or a string.
- *
- * @return bool
- * TRUE if the operation succeeded, FALSE otherwise.
- *
- * @see omega_drush_replace_contents()
- * @see str_replace()
- */
- function drush_basic_rewrite_recursive($path, $search, $replace) {
- if (!is_dir($path)) {
- return drush_set_error('INVALID_PATH', dt('The given path !path is not a directory.', array(
- '!path' => $path,
- )));
- }
- // If the file actually is a directory, proceed with the recursion.
- $directory = new DirectoryIterator($path);
- foreach ($directory as $item) {
- if ($item->isDot()) {
- // Do not process '..' and '.'.
- continue;
- }
- // Retrieve the path of the current item.
- $pathname = $item->getPathname();
- if ($item->isDir() && !drush_basic_rewrite_recursive($pathname, $search, $replace)) {
- return FALSE;
- }
- elseif ($item->isFile()) {
- // If it is a file, try to replace its contents.
- $content = file_get_contents($pathname);
- // Nothing to replace in empty files.
- if (empty($content)) {
- unlink($pathname);
- continue;
- }
- if (($changed_content = str_replace($search, $replace, $content)) === NULL) {
- return drush_set_error('REWRITE_FAILURE', dt('There was an error while trying to rewrite !path (!search to !replace)', array(
- '!path' => $pathname,
- '!search' => $search,
- '!replace' => $replace,
- )));
- }
- if ($content !== $changed_content) {
- file_put_contents($pathname, $changed_content);
- }
- }
- }
- return TRUE;
- }
- /**
- * Copy $src to $dest.
- *
- * @param string $src
- * The directory to copy.
- * @param string $dest
- * The destination to copy the source to, including the new name of
- * the directory. To copy directory "a" from "/b" to "/c", then
- * $src = "/b/a" and $dest = "/c/a". To copy "a" to "/c" and rename
- * it to "d", then $dest = "/c/d".
- * @param int $overwrite
- * Action to take if destination already exists.
- * - FILE_EXISTS_OVERWRITE - completely removes existing directory.
- * - FILE_EXISTS_ABORT - aborts the operation.
- * - FILE_EXISTS_MERGE - Leaves existing files and directories in place.
- *
- * @return bool
- * TRUE on success, FALSE on failure.
- */
- function basic_copy_dir($src, $dest, $overwrite = FILE_EXISTS_ABORT) {
- // Preflight based on $overwrite if $dest exists.
- if (file_exists($dest)) {
- if ($overwrite === FILE_EXISTS_OVERWRITE) {
- drush_op('drush_delete_dir', $dest, TRUE);
- }
- elseif ($overwrite === FILE_EXISTS_ABORT) {
- return drush_set_error('DRUSH_DESTINATION_EXISTS', dt('Destination directory !dest already exists.', array('!dest' => $dest)));
- }
- elseif ($overwrite === FILE_EXISTS_MERGE) {
- // $overwrite flag may indicate we should merge instead.
- drush_log(dt('Merging existing !dest directory', array('!dest' => $dest)));
- }
- }
- // $src readable?
- if (!is_readable($src)) {
- return drush_set_error('DRUSH_SOURCE_NOT_EXISTS', dt('Source directory !src is not readable or does not exist.', array('!src' => $src)));
- }
- // $dest writable?
- if (!is_writable(dirname($dest))) {
- return drush_set_error('DRUSH_DESTINATION_NOT_WRITABLE', dt('Destination directory !dest is not writable.', array('!dest' => dirname($dest))));
- }
- // Try to do a recursive copy.
- if (@drush_op('_basic_recursive_copy', $src, $dest)) {
- return TRUE;
- }
- return drush_set_error('DRUSH_COPY_DIR_FAILURE', dt('Unable to copy !src to !dest.', array('!src' => $src, '!dest' => $dest)));
- }
- /**
- * Internal function called by basic_copy_dir; do not use directly.
- */
- function _basic_recursive_copy($src, $destination) {
- static $machine_name;
- if (!isset($machine_name)) {
- $machine_name = drush_get_option('machine-name');
- }
- // All subdirectories and contents.
- $ignore_directories = array(
- 'node_modules',
- );
- $no_mask = '/^' . implode('|', $ignore_directories) . '$/';
- if (is_dir($src)) {
- if (!drush_mkdir($destination, TRUE)) {
- return FALSE;
- }
- $dir_handle = opendir($src);
- while ($file = readdir($dir_handle)) {
- if (($file[0] != '.' || $file == '.gitignore') && !preg_match($no_mask, $file)) {
- if (_basic_recursive_copy("$src/$file", "$destination/$file") !== TRUE) {
- return FALSE;
- }
- }
- }
- closedir($dir_handle);
- }
- elseif (is_link($src)) {
- symlink(readlink($src), $destination);
- }
- elseif (!copy($src, $destination)) {
- return FALSE;
- }
- // Rename files with basic.
- if (strpos($destination, 'basic') !== FALSE) {
- $renamed_destination = str_replace('basic', $machine_name, $destination);
- rename($destination, $renamed_destination);
- }
- // Preserve file modification time.
- touch($destination, filemtime($src));
- // Preserve execute permission.
- if (!is_link($src) && !drush_is_windows()) {
- // Get execute bits of $src.
- $execperms = fileperms($src) & 0111;
- // Apply execute permissions if any.
- if ($execperms > 0) {
- $perms = fileperms($destination) | $execperms;
- chmod($destination, $perms);
- }
- }
- return TRUE;
- }
- /**
- * Recursively removes all files within the provided directory.
- *
- * USE WITH CAUTION.
- *
- * @param string $dir
- * File path for the directory you want to delete.
- */
- function basic_rm_dir($dir) {
- if (is_dir($dir)) {
- $objects = scandir($dir);
- foreach ($objects as $object) {
- if ($object != "." && $object != "..") {
- if (is_dir($dir . "/" . $object)) {
- basic_rm_dir($dir . "/" . $object);
- }
- else {
- unlink($dir . "/" . $object);
- }
- }
- }
- rmdir($dir);
- }
- }
|