diff --git a/bin/install-jsdeps.sh b/bin/install-jsdeps.sh index 347ae851e..785c84e32 100755 --- a/bin/install-jsdeps.sh +++ b/bin/install-jsdeps.sh @@ -23,14 +23,14 @@ define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' ); require_once INSTALL_PATH . 'program/include/clisetup.php'; if (!function_exists('exec')) { - rcube::raise_error("PHP exec() function is required. Check disable_functions in php.ini.", false, true); + rcube::raise_error("PHP exec() function is required. Check disable_functions in php.ini.", false, true); } $cfgfile = INSTALL_PATH . 'jsdeps.json'; $SOURCES = json_decode(file_get_contents($cfgfile), true); if (empty($SOURCES['dependencies'])) { - rcube::raise_error("Failed to read dependencies list from $cfgfile", false, true); + rcube::raise_error("Failed to read dependencies list from $cfgfile", false, true); } $CURL = trim(`which curl`); @@ -39,13 +39,13 @@ $UNZIP = trim(`which unzip`); $FILEINFO = trim(`which file`); if (($CACHEDIR = getenv("CACHEDIR")) && is_writeable($CACHEDIR)) { - // use $CACHEDIR + // use $CACHEDIR } else if (is_writeable(INSTALL_PATH . 'temp/js_cache') || @mkdir(INSTALL_PATH . 'temp/js_cache', 0774, true)) { - $CACHEDIR = INSTALL_PATH . 'temp/js_cache'; + $CACHEDIR = INSTALL_PATH . 'temp/js_cache'; } else { - $CACHEDIR = sys_get_temp_dir(); + $CACHEDIR = sys_get_temp_dir(); } @@ -110,43 +110,43 @@ EOL; */ function fetch_from_source($package, $useCache = true, &$filetype = null) { - global $CURL, $WGET; + global $CURL, $WGET; - $cache_file = extract_filetype($package, $filetype); + $cache_file = extract_filetype($package, $filetype); - if (!is_readable($cache_file) || !$useCache) { - if (empty($CURL) && empty($WGET)) { - rcube::raise_error("Required 'wget' or 'curl' program not found.", false, true); - } + if (!is_readable($cache_file) || !$useCache) { + if (empty($CURL) && empty($WGET)) { + rcube::raise_error("Required 'wget' or 'curl' program not found.", false, true); + } - $url = str_replace('$v', $package['version'], $package['url']); + $url = str_replace('$v', $package['version'], $package['url']); - echo "Fetching $url\n"; + echo "Fetching $url\n"; - if ($CURL) - exec(sprintf('%s -L -s %s -o %s', $CURL, escapeshellarg($url), $cache_file), $out, $retval); - else - exec(sprintf('%s -q %s -O %s', $WGET, escapeshellarg($url), $cache_file), $out, $retval); + if ($CURL) + exec(sprintf('%s -L -s %s -o %s', $CURL, escapeshellarg($url), $cache_file), $out, $retval); + else + exec(sprintf('%s -q %s -O %s', $WGET, escapeshellarg($url), $cache_file), $out, $retval); - // Try Github API as a fallback (#6248) - if ($retval !== 0 && $package['api_url']) { - $url = str_replace('$v', $package['version'], $package['api_url']); - $header = 'Accept:application/vnd.github.v3.raw'; + // Try Github API as a fallback (#6248) + if ($retval !== 0 && $package['api_url']) { + $url = str_replace('$v', $package['version'], $package['api_url']); + $header = 'Accept:application/vnd.github.v3.raw'; - rcube::raise_error("Fetching failed. Using Github API on $url"); + rcube::raise_error("Fetching failed. Using Github API on $url"); - if ($CURL) - exec(sprintf('%s -L -H %s -s %s -o %s', $CURL, escapeshellarg($header), escapeshellarg($url), $cache_file), $out, $retval); - else - exec(sprintf('%s --header %s -q %s -O %s', $WGET, escapeshellarg($header), escapeshellarg($url), $cache_file), $out, $retval); - } + if ($CURL) + exec(sprintf('%s -L -H %s -s %s -o %s', $CURL, escapeshellarg($header), escapeshellarg($url), $cache_file), $out, $retval); + else + exec(sprintf('%s --header %s -q %s -O %s', $WGET, escapeshellarg($header), escapeshellarg($url), $cache_file), $out, $retval); + } - if ($retval !== 0) { - rcube::raise_error("Failed to download source file from $url", false, true); + if ($retval !== 0) { + rcube::raise_error("Failed to download source file from $url", false, true); + } } - } - return $cache_file; + return $cache_file; } /** @@ -154,22 +154,22 @@ function fetch_from_source($package, $useCache = true, &$filetype = null) */ function extract_filetype($package, &$filetype = null) { - global $FILEINFO, $CACHEDIR; + global $FILEINFO, $CACHEDIR; - $filetype = pathinfo($package['url'], PATHINFO_EXTENSION) ?: 'tmp'; - $cache_file = $CACHEDIR . '/' . $package['lib'] . '-' . $package['version'] . '.' . $filetype; + $filetype = pathinfo($package['url'], PATHINFO_EXTENSION) ?: 'tmp'; + $cache_file = $CACHEDIR . '/' . $package['lib'] . '-' . $package['version'] . '.' . $filetype; - if (empty($FILEINFO)) { - rcube::raise_error("Required program 'file' not found.", false, true); - } + if (empty($FILEINFO)) { + rcube::raise_error("Required program 'file' not found.", false, true); + } - // detect downloaded/cached file type - exec(sprintf('%s -b %s', $FILEINFO, $cache_file), $out); - if (stripos($out[0], 'zip') === 0) { - $filetype = 'zip'; - } + // detect downloaded/cached file type + exec(sprintf('%s -b %s', $FILEINFO, $cache_file), $out); + if (stripos($out[0], 'zip') === 0) { + $filetype = 'zip'; + } - return $cache_file; + return $cache_file; } /** @@ -177,38 +177,38 @@ function extract_filetype($package, &$filetype = null) */ function compose_destfile($package, $srcfile) { - global $LICENSES; - - $header = sprintf("/**\n * %s - v%s\n *\n", $package['name'], $package['version']); - - if (!empty($package['source'])) { - $header .= " * @source " . str_replace('$v', $package['version'], $package['source']) . "\n"; - $header .= " *\n"; - } - - if (!empty($package['license']) && isset($LICENSES[$package['license']])) { - $header .= " * @licstart The following is the entire license notice for the\n"; - $header .= " * JavaScript code in this file.\n"; - $header .= " *\n"; - if (!empty($package['copyright'])) { - $header .= " * " . $package['copyright'] . "\n"; - $header .= " *\n"; + global $LICENSES; + + $header = sprintf("/**\n * %s - v%s\n *\n", $package['name'], $package['version']); + + if (!empty($package['source'])) { + $header .= " * @source " . str_replace('$v', $package['version'], $package['source']) . "\n"; + $header .= " *\n"; } - $header .= $LICENSES[$package['license']]; - $header .= " *\n"; - $header .= " * @licend The above is the entire license notice\n"; - $header .= " * for the JavaScript code in this file.\n"; - } + if (!empty($package['license']) && isset($LICENSES[$package['license']])) { + $header .= " * @licstart The following is the entire license notice for the\n"; + $header .= " * JavaScript code in this file.\n"; + $header .= " *\n"; + if (!empty($package['copyright'])) { + $header .= " * " . $package['copyright'] . "\n"; + $header .= " *\n"; + } + + $header .= $LICENSES[$package['license']]; + $header .= " *\n"; + $header .= " * @licend The above is the entire license notice\n"; + $header .= " * for the JavaScript code in this file.\n"; + } - $header .= " */\n"; + $header .= " */\n"; - if (file_put_contents(INSTALL_PATH . $package['dest'], $header . file_get_contents($srcfile))) { - echo "Wrote file " . INSTALL_PATH . $package['dest'] . "\n"; - } - else { - rcube::raise_error("Failed to write destination file " . INSTALL_PATH . $package['dest'], false, true); - } + if (file_put_contents(INSTALL_PATH . $package['dest'], $header . file_get_contents($srcfile))) { + echo "Wrote file " . INSTALL_PATH . $package['dest'] . "\n"; + } + else { + rcube::raise_error("Failed to write destination file " . INSTALL_PATH . $package['dest'], false, true); + } } /** @@ -216,94 +216,94 @@ function compose_destfile($package, $srcfile) */ function extract_zipfile($package, $srcfile) { - global $UNZIP, $CACHEDIR; - - if (empty($UNZIP)) { - rcube::raise_error("Required 'unzip' program not found.", false, true); - } - - $destdir = INSTALL_PATH . $package['dest']; - if (!is_dir($destdir)) { - mkdir($destdir, 0775, true); - } - - if (!is_writeable($destdir)) { - rcube::raise_error("Cannot write to destination directory: $destdir", false, true); - } - - // pick files from zip archive - if (!empty($package['pick'])) { - foreach ($package['pick'] as $pattern) { - echo "Extracting files $pattern into $destdir\n"; - exec(sprintf('%s -o %s %s -d %s', $UNZIP, escapeshellarg($srcfile), escapeshellarg($pattern), $destdir), $out, $retval); - if ($retval !== 0) { - rcube::raise_error("Failed to unpack $pattern; " . join('; ' . $out)); - } - } - } - // unzip the archive and map source to dest files/directories - else if (!empty($package['map'])) { - $extract = $CACHEDIR . '/' . $package['lib'] . '-extract'; - if (!is_dir($extract)) { - mkdir($extract, 0774, true); - } + global $UNZIP, $CACHEDIR; - $zip_command = '%s -' . ($package['flat'] ? 'j' : 'o') . ' %s -d %s'; - exec(sprintf($zip_command, $UNZIP, escapeshellarg($srcfile), $extract), $out, $retval); + if (empty($UNZIP)) { + rcube::raise_error("Required 'unzip' program not found.", false, true); + } - // get the root folder of the extracted package - $extract_tree = glob("$extract/*", GLOB_ONLYDIR); - $sourcedir = count($extract_tree) ? $extract_tree[0] : $extract; + $destdir = INSTALL_PATH . $package['dest']; + if (!is_dir($destdir)) { + mkdir($destdir, 0775, true); + } - foreach ($package['map'] as $src => $dest) { - echo "Installing $sourcedir/$src into $destdir/$dest\n"; + if (!is_writeable($destdir)) { + rcube::raise_error("Cannot write to destination directory: $destdir", false, true); + } - // make sure the destination's parent directory exists - if (strpos($dest, '/') !== false) { - $parentdir = dirname($destdir . '/' . $dest); - if (!is_dir($parentdir)) { - mkdir($parentdir, 0775, true); + // pick files from zip archive + if (!empty($package['pick'])) { + foreach ($package['pick'] as $pattern) { + echo "Extracting files $pattern into $destdir\n"; + exec(sprintf('%s -o %s %s -d %s', $UNZIP, escapeshellarg($srcfile), escapeshellarg($pattern), $destdir), $out, $retval); + if ($retval !== 0) { + rcube::raise_error("Failed to unpack $pattern; " . join('; ' . $out)); + } + } + } + // unzip the archive and map source to dest files/directories + else if (!empty($package['map'])) { + $extract = $CACHEDIR . '/' . $package['lib'] . '-extract'; + if (!is_dir($extract)) { + mkdir($extract, 0774, true); } - } - // avoid copying source directory as a child into destination - if (is_dir($sourcedir . '/' . $src) && is_dir($destdir . '/' . $dest)) { - exec(sprintf('rm -rf %s/%s', $destdir, $dest)); - } + $zip_command = '%s -' . ($package['flat'] ? 'j' : 'o') . ' %s -d %s'; + exec(sprintf($zip_command, $UNZIP, escapeshellarg($srcfile), $extract), $out, $retval); + + // get the root folder of the extracted package + $extract_tree = glob("$extract/*", GLOB_ONLYDIR); + $sourcedir = count($extract_tree) ? $extract_tree[0] : $extract; + + foreach ($package['map'] as $src => $dest) { + echo "Installing $sourcedir/$src into $destdir/$dest\n"; + + // make sure the destination's parent directory exists + if (strpos($dest, '/') !== false) { + $parentdir = dirname($destdir . '/' . $dest); + if (!is_dir($parentdir)) { + mkdir($parentdir, 0775, true); + } + } + + // avoid copying source directory as a child into destination + if (is_dir($sourcedir . '/' . $src) && is_dir($destdir . '/' . $dest)) { + exec(sprintf('rm -rf %s/%s', $destdir, $dest)); + } + + exec(sprintf('mv -f %s/%s %s/%s', $sourcedir, $src, $destdir, $dest), $out, $retval); + if ($retval !== 0) { + rcube::raise_error("Failed to move $src into $destdir/$dest; " . join('; ' . $out)); + } + } - exec(sprintf('mv -f %s/%s %s/%s', $sourcedir, $src, $destdir, $dest), $out, $retval); - if ($retval !== 0) { - rcube::raise_error("Failed to move $src into $destdir/$dest; " . join('; ' . $out)); - } + // remove temp extraction dir + exec('rm -rf ' . $extract); } - - // remove temp extraction dir - exec('rm -rf ' . $extract); - } - // extract the archive into the destination directory - else { - echo "Extracting zip archive into $destdir\n"; - exec(sprintf('%s -o %s -d %s', $UNZIP, escapeshellarg($srcfile), $destdir), $out, $retval); - if ($retval !== 0) { - rcube::raise_error("Failed to unzip $srcfile; " . join('; ' . $out)); + // extract the archive into the destination directory + else { + echo "Extracting zip archive into $destdir\n"; + exec(sprintf('%s -o %s -d %s', $UNZIP, escapeshellarg($srcfile), $destdir), $out, $retval); + if ($retval !== 0) { + rcube::raise_error("Failed to unzip $srcfile; " . join('; ' . $out)); + } } - } - // remove some files from the destination - if (!empty($package['omit'])) { - foreach ((array)$package['omit'] as $glob) { - exec(sprintf('rm -rf %s/%s', $destdir, escapeshellarg($glob))); + // remove some files from the destination + if (!empty($package['omit'])) { + foreach ((array)$package['omit'] as $glob) { + exec(sprintf('rm -rf %s/%s', $destdir, escapeshellarg($glob))); + } } - } - - // prepend license header to extracted files - if (!empty($package['addlicense'])) { - foreach ((array)$package['addlicense'] as $filename) { - $pkg = $package; - $pkg['dest'] = $package['dest'] . '/' . $filename; - compose_destfile($pkg, $destdir . '/' . $filename); + + // prepend license header to extracted files + if (!empty($package['addlicense'])) { + foreach ((array)$package['addlicense'] as $filename) { + $pkg = $package; + $pkg['dest'] = $package['dest'] . '/' . $filename; + compose_destfile($pkg, $destdir . '/' . $filename); + } } - } } /** @@ -311,16 +311,16 @@ function extract_zipfile($package, $srcfile) */ function delete_destfile($package) { - $destdir = INSTALL_PATH . ($package['rm'] ?: $package['dest']); + $destdir = INSTALL_PATH . ($package['rm'] ?: $package['dest']); - if (file_exists($destdir)) { - if (PHP_OS === 'Windows') { - exec(sprintf("rd /s /q %s", escapeshellarg($destdir))); - } - else { - exec(sprintf("rm -rf %s", escapeshellarg($destdir))); + if (file_exists($destdir)) { + if (PHP_OS === 'Windows') { + exec(sprintf("rd /s /q %s", escapeshellarg($destdir))); + } + else { + exec(sprintf("rm -rf %s", escapeshellarg($destdir))); + } } - } } @@ -332,44 +332,44 @@ $WHAT = $args[0]; $useCache = !$args['force'] && !$args['get']; if (!$args['get'] && !$args['extract'] && !$args['delete']) { - $args['get'] = $args['extract'] = 1; + $args['get'] = $args['extract'] = 1; } foreach ($SOURCES['dependencies'] as $package) { - if (!isset($package['name'])) { - $package['name'] = $package['lib']; - } - - if ($WHAT && $package['lib'] !== $WHAT) { - continue; - } - - if ($args['delete']) { - delete_destfile($package); - continue; - } - - if ($args['get']) { - $srcfile = fetch_from_source($package, $useCache, $filetype); - } - else { - $srcfile = extract_filetype($package, $filetype); - } - - if (!empty($package['sha1']) && ($sum = sha1_file($srcfile)) !== $package['sha1']) { - rcube::raise_error("Incorrect sha1 sum of $srcfile. Expected: {$package['sha1']}, got: $sum", false, true); - } - - if ($args['extract']) { - echo "Installing {$package['name']}...\n"; - - if ($filetype === 'zip') { - extract_zipfile($package, $srcfile); + if (!isset($package['name'])) { + $package['name'] = $package['lib']; + } + + if ($WHAT && $package['lib'] !== $WHAT) { + continue; + } + + if ($args['delete']) { + delete_destfile($package); + continue; + } + + if ($args['get']) { + $srcfile = fetch_from_source($package, $useCache, $filetype); } else { - compose_destfile($package, $srcfile); + $srcfile = extract_filetype($package, $filetype); + } + + if (!empty($package['sha1']) && ($sum = sha1_file($srcfile)) !== $package['sha1']) { + rcube::raise_error("Incorrect sha1 sum of $srcfile. Expected: {$package['sha1']}, got: $sum", false, true); } - echo "Done.\n"; - } + if ($args['extract']) { + echo "Installing {$package['name']}...\n"; + + if ($filetype === 'zip') { + extract_zipfile($package, $srcfile); + } + else { + compose_destfile($package, $srcfile); + } + + echo "Done.\n"; + } } diff --git a/bin/installto.sh b/bin/installto.sh index 0450e1878..291bebf71 100755 --- a/bin/installto.sh +++ b/bin/installto.sh @@ -23,116 +23,120 @@ define('INSTALL_PATH', realpath(__DIR__ . '/..') . '/' ); require_once INSTALL_PATH . 'program/include/clisetup.php'; if (!function_exists('system')) { - rcube::raise_error("PHP system() function is required. Check disable_functions in php.ini.", false, true); + rcube::raise_error("PHP system() function is required. Check disable_functions in php.ini.", false, true); } $target_dir = unslashify($_SERVER['argv'][1]); if (empty($target_dir) || !is_dir(realpath($target_dir))) - rcube::raise_error("Invalid target: not a directory\nUsage: installto.sh ", false, true); + rcube::raise_error("Invalid target: not a directory\nUsage: installto.sh ", false, true); // read version from iniset.php $iniset = @file_get_contents($target_dir . '/program/include/iniset.php'); if (!preg_match('/define\(.RCMAIL_VERSION.,\s*.([0-9.]+[a-z-]*)/', $iniset, $m)) - rcube::raise_error("No valid Roundcube installation found at $target_dir", false, true); + rcube::raise_error("No valid Roundcube installation found at $target_dir", false, true); $oldversion = $m[1]; if (version_compare(version_parse($oldversion), version_parse(RCMAIL_VERSION), '>')) - rcube::raise_error("Target installation already in version $oldversion.", false, true); + rcube::raise_error("Target installation already in version $oldversion.", false, true); if (version_compare(version_parse($oldversion), version_parse(RCMAIL_VERSION), '==')) { - echo "Target installation already in version $oldversion. Do you want to update again? (y/N)\n"; + echo "Target installation already in version $oldversion. Do you want to update again? (y/N)\n"; } else { - echo "Upgrading from $oldversion. Do you want to continue? (y/N)\n"; + echo "Upgrading from $oldversion. Do you want to continue? (y/N)\n"; } $input = trim(fgets(STDIN)); if (strtolower($input) == 'y') { - echo "Copying files to target location..."; - - $adds = array(); - $dirs = array('bin','SQL','plugins','skins','program'); - - if (is_dir(INSTALL_PATH . 'vendor') && !is_file("$target_dir/composer.json")) { - $dirs[] = 'vendor'; - } - if (file_exists("$target_dir/installer")) { - $dirs[] = 'installer'; - } - - foreach ($dirs as $dir) { - // @FIXME: should we use --delete for all directories? - $delete = in_array($dir, array('program', 'vendor', 'installer')) ? '--delete ' : ''; - $command = "rsync -aC --out-format=%n " . $delete . INSTALL_PATH . "$dir/ $target_dir/$dir/"; - if (system($command, $ret) === false || $ret > 0) { - rcube::raise_error("Failed to execute command: $command", false, true); + echo "Copying files to target location..."; + + $adds = array(); + $dirs = array('bin','SQL','plugins','skins','program'); + + if (is_dir(INSTALL_PATH . 'vendor') && !is_file("$target_dir/composer.json")) { + $dirs[] = 'vendor'; + } + if (file_exists("$target_dir/installer")) { + $dirs[] = 'installer'; } - } - foreach (array('index.php','config/defaults.inc.php','composer.json-dist','jsdeps.json','CHANGELOG','README.md','UPGRADING','LICENSE','INSTALL') as $file) { - $command = "rsync -a --out-format=%n " . INSTALL_PATH . "$file $target_dir/$file"; - if (file_exists(INSTALL_PATH . $file) && (system($command, $ret) === false || $ret > 0)) { - rcube::raise_error("Failed to execute command: $command", false, true); + foreach ($dirs as $dir) { + // @FIXME: should we use --delete for all directories? + $delete = in_array($dir, array('program', 'vendor', 'installer')) ? '--delete ' : ''; + $command = "rsync -aC --out-format=%n " . $delete . INSTALL_PATH . "$dir/ $target_dir/$dir/"; + + if (system($command, $ret) === false || $ret > 0) { + rcube::raise_error("Failed to execute command: $command", false, true); + } } - } - - // Copy .htaccess or .user.ini if needed - foreach (array('.htaccess','.user.ini') as $file) { - if (file_exists(INSTALL_PATH . $file)) { - if (!file_exists("$target_dir/$file") || file_get_contents(INSTALL_PATH . $file) != file_get_contents("$target_dir/$file")) { - if (copy(INSTALL_PATH . $file, "$target_dir/$file.new")) { - echo "$file.new\n"; - $adds[] = "NOTICE: New $file file saved as $file.new."; + + foreach (array('index.php','config/defaults.inc.php','composer.json-dist','jsdeps.json','CHANGELOG','README.md','UPGRADING','LICENSE','INSTALL') as $file) { + $command = "rsync -a --out-format=%n " . INSTALL_PATH . "$file $target_dir/$file"; + + if (file_exists(INSTALL_PATH . $file) && (system($command, $ret) === false || $ret > 0)) { + rcube::raise_error("Failed to execute command: $command", false, true); } - } } - } - - // remove old (<1.0) .htaccess file - @unlink("$target_dir/program/.htaccess"); - echo "done.\n\n"; - - if (is_dir("$target_dir/skins/default")) { - echo "Removing old default skin..."; - system("rm -rf $target_dir/skins/default $target_dir/plugins/jqueryui/themes/default"); - foreach (glob(INSTALL_PATH . "plugins/*/skins") as $plugin_skin_dir) { - $plugin_skin_dir = preg_replace('!^.*' . INSTALL_PATH . '!', '', $plugin_skin_dir); - if (is_dir("$target_dir/$plugin_skin_dir/classic")) - system("rm -rf $target_dir/$plugin_skin_dir/default"); - } - echo "done.\n\n"; - } - - // check if js-deps are up-to-date - if (file_exists("$target_dir/jsdeps.json") && file_exists("$target_dir/bin/install-jsdeps.sh")) { - $jsdeps = json_decode(file_get_contents("$target_dir/jsdeps.json")); - $package = $jsdeps->dependencies[0]; - $dest_file = $target_dir . '/' . $package->dest; - if (!file_exists($dest_file) || sha1_file($dest_file) !== $package->sha1) { - echo "Installing JavaScript dependencies..."; - system("cd $target_dir && bin/install-jsdeps.sh"); + + // Copy .htaccess or .user.ini if needed + foreach (array('.htaccess','.user.ini') as $file) { + if (file_exists(INSTALL_PATH . $file)) { + if (!file_exists("$target_dir/$file") || file_get_contents(INSTALL_PATH . $file) != file_get_contents("$target_dir/$file")) { + if (copy(INSTALL_PATH . $file, "$target_dir/$file.new")) { + echo "$file.new\n"; + $adds[] = "NOTICE: New $file file saved as $file.new."; + } + } + } + } + + // remove old (<1.0) .htaccess file + @unlink("$target_dir/program/.htaccess"); + echo "done.\n\n"; + + if (is_dir("$target_dir/skins/default")) { + echo "Removing old default skin..."; + system("rm -rf $target_dir/skins/default $target_dir/plugins/jqueryui/themes/default"); + foreach (glob(INSTALL_PATH . "plugins/*/skins") as $plugin_skin_dir) { + $plugin_skin_dir = preg_replace('!^.*' . INSTALL_PATH . '!', '', $plugin_skin_dir); + if (is_dir("$target_dir/$plugin_skin_dir/classic")) { + system("rm -rf $target_dir/$plugin_skin_dir/default"); + } + } echo "done.\n\n"; } - } - else { - $adds[] = "NOTICE: JavaScript dependencies installation skipped..."; - } - - if (file_exists("$target_dir/installer")) { - $adds[] = "NOTICE: The 'installer' directory still exists. You should remove it after the upgrade."; - } - - if (!empty($adds)) { - echo implode($adds, "\n") . "\n\n"; - } - - echo "Running update script at target...\n"; - system("cd $target_dir && php bin/update.sh --version=$oldversion"); - echo "All done.\n"; + + // check if js-deps are up-to-date + if (file_exists("$target_dir/jsdeps.json") && file_exists("$target_dir/bin/install-jsdeps.sh")) { + $jsdeps = json_decode(file_get_contents("$target_dir/jsdeps.json")); + $package = $jsdeps->dependencies[0]; + $dest_file = $target_dir . '/' . $package->dest; + + if (!file_exists($dest_file) || sha1_file($dest_file) !== $package->sha1) { + echo "Installing JavaScript dependencies..."; + system("cd $target_dir && bin/install-jsdeps.sh"); + echo "done.\n\n"; + } + } + else { + $adds[] = "NOTICE: JavaScript dependencies installation skipped..."; + } + + if (file_exists("$target_dir/installer")) { + $adds[] = "NOTICE: The 'installer' directory still exists. You should remove it after the upgrade."; + } + + if (!empty($adds)) { + echo implode($adds, "\n") . "\n\n"; + } + + echo "Running update script at target...\n"; + system("cd $target_dir && php bin/update.sh --version=$oldversion"); + echo "All done.\n"; } else { - echo "Update cancelled. See ya!\n"; + echo "Update cancelled. See ya!\n"; } diff --git a/bin/update.sh b/bin/update.sh index b1315e823..2756db50b 100755 --- a/bin/update.sh +++ b/bin/update.sh @@ -27,247 +27,262 @@ $opts = rcube_utils::get_opt(array('v' => 'version', 'y' => 'accept:bool')); // ask user if no version is specified if (!$opts['version']) { - echo "What version are you upgrading from? Type '?' if you don't know.\n"; - if (($input = trim(fgets(STDIN))) && preg_match('/^[0-9.]+[a-z-]*$/', $input)) - $opts['version'] = $input; - else - $opts['version'] = RCMAIL_VERSION; + echo "What version are you upgrading from? Type '?' if you don't know.\n"; + + if (($input = trim(fgets(STDIN))) && preg_match('/^[0-9.]+[a-z-]*$/', $input)) { + $opts['version'] = $input; + } + else { + $opts['version'] = RCMAIL_VERSION; + } } $RCI = rcmail_install::get_instance(); $RCI->load_config(); if ($RCI->configured) { - $success = true; - - if (($messages = $RCI->check_config()) || $RCI->legacy_config) { - $success = false; - $err = 0; - - // list old/replaced config options - if (is_array($messages['replaced'])) { - echo "WARNING: Replaced config options:\n"; - echo "(These config options have been replaced or renamed)\n"; - - foreach ($messages['replaced'] as $msg) { - echo "- '" . $msg['prop'] . "' was replaced by '" . $msg['replacement'] . "'\n"; - $err++; - } - echo "\n"; - } - - // list obsolete config options (just a notice) - if (is_array($messages['obsolete'])) { - echo "NOTICE: Obsolete config options:\n"; - echo "(You still have some obsolete or inexistent properties set. This isn't a problem but should be noticed)\n"; + $success = true; - foreach ($messages['obsolete'] as $msg) { - echo "- '" . $msg['prop'] . ($msg['name'] ? "': " . $msg['name'] : "'") . "\n"; - $err++; - } - echo "\n"; - } + if (($messages = $RCI->check_config()) || $RCI->legacy_config) { + $success = false; + $err = 0; - if (!$err && $RCI->legacy_config) { - echo "WARNING: Your configuration needs to be migrated!\n"; - echo "We changed the configuration files structure and your two config files main.inc.php and db.inc.php have to be merged into one single file.\n"; - $err++; - } + // list old/replaced config options + if (is_array($messages['replaced'])) { + echo "WARNING: Replaced config options:\n"; + echo "(These config options have been replaced or renamed)\n"; - // ask user to update config files - if ($err) { - if (!$opts['accept']) { - echo "Do you want me to fix your local configuration? (y/N)\n"; - $input = trim(fgets(STDIN)); - } + foreach ($messages['replaced'] as $msg) { + echo "- '" . $msg['prop'] . "' was replaced by '" . $msg['replacement'] . "'\n"; + $err++; + } - // positive: let's merge the local config with the defaults - if ($opts['accept'] || strtolower($input) == 'y') { - $error = $written = false; + echo "\n"; + } - // backup current config - echo ". backing up the current config file(s)...\n"; + // list obsolete config options (just a notice) + if (is_array($messages['obsolete'])) { + echo "NOTICE: Obsolete config options:\n"; + echo "(You still have some obsolete or inexistent properties set." + . " This isn't a problem but should be noticed)\n"; - foreach (array('config', 'main', 'db') as $file) { - if (file_exists(RCMAIL_CONFIG_DIR . '/' . $file . '.inc.php')) { - if (!copy(RCMAIL_CONFIG_DIR . '/' . $file . '.inc.php', RCMAIL_CONFIG_DIR . '/' . $file . '.old.php')) { - $error = true; + foreach ($messages['obsolete'] as $msg) { + echo "- '" . $msg['prop'] . ($msg['name'] ? "': " . $msg['name'] : "'") . "\n"; + $err++; } - } - } - if (!$error) { - $RCI->merge_config(); - echo ". writing " . RCMAIL_CONFIG_DIR . "/config.inc.php...\n"; - $written = $RCI->save_configfile($RCI->create_config()); + echo "\n"; } - // Success! - if ($written) { - echo "Done.\n"; - echo "Your configuration files are now up-to-date!\n"; + if (!$err && $RCI->legacy_config) { + echo "WARNING: Your configuration needs to be migrated!\n"; + echo "We changed the configuration files structure and your two config files " + . "main.inc.php and db.inc.php have to be merged into one single file.\n"; + $err++; + } - if ($messages['missing']) { - echo "But you still need to add the following missing options:\n"; - foreach ($messages['missing'] as $msg) - echo "- '" . $msg['prop'] . ($msg['name'] ? "': " . $msg['name'] : "'") . "\n"; - } + // ask user to update config files + if ($err) { + if (!$opts['accept']) { + echo "Do you want me to fix your local configuration? (y/N)\n"; + $input = trim(fgets(STDIN)); + } - if ($RCI->legacy_config) { - foreach (array('main', 'db') as $file) { - @unlink(RCMAIL_CONFIG_DIR . '/' . $file . '.inc.php'); + // positive: merge the local config with the defaults + if ($opts['accept'] || strtolower($input) == 'y') { + $error = $written = false; + + echo ". backing up the current config file(s)...\n"; + + foreach (array('config', 'main', 'db') as $file) { + if (file_exists(RCMAIL_CONFIG_DIR . '/' . $file . '.inc.php')) { + if (!copy(RCMAIL_CONFIG_DIR . '/' . $file . '.inc.php', RCMAIL_CONFIG_DIR . '/' . $file . '.old.php')) { + $error = true; + } + } + } + + if (!$error) { + $RCI->merge_config(); + echo ". writing " . RCMAIL_CONFIG_DIR . "/config.inc.php...\n"; + $written = $RCI->save_configfile($RCI->create_config()); + } + + // Success! + if ($written) { + echo "Done.\n"; + echo "Your configuration files are now up-to-date!\n"; + + if ($messages['missing']) { + echo "But you still need to add the following missing options:\n"; + foreach ($messages['missing'] as $msg) { + echo "- '" . $msg['prop'] . ($msg['name'] ? "': " . $msg['name'] : "'") . "\n"; + } + } + + if ($RCI->legacy_config) { + foreach (array('main', 'db') as $file) { + @unlink(RCMAIL_CONFIG_DIR . '/' . $file . '.inc.php'); + } + } + } + else { + echo "Failed to write config file(s)!\n"; + echo "Grant write privileges to the current user or update the files manually " + . "according to the above messages.\n"; + } + } + else { + echo "Please update your config files manually according to the above messages.\n"; } - } } - else { - echo "Failed to write config file(s)!\n"; - echo "Grant write privileges to the current user or update the files manually according to the above messages.\n"; + + // check dependencies based on the current configuration + if (is_array($messages['dependencies'])) { + echo "WARNING: Dependency check failed!\n"; + echo "(Some of your configuration settings require other options to be configured " + . "or additional PHP modules to be installed)\n"; + + foreach ($messages['dependencies'] as $msg) { + echo "- " . $msg['prop'] . ': ' . $msg['explain'] . "\n"; + } + + echo "Please fix your config files and run this script again!\n"; + echo "See ya.\n"; } - } - else { - echo "Please update your config files manually according to the above messages.\n"; - } } - // check dependencies based on the current configuration - if (is_array($messages['dependencies'])) { - echo "WARNING: Dependency check failed!\n"; - echo "(Some of your configuration settings require other options to be configured or additional PHP modules to be installed)\n"; - - foreach ($messages['dependencies'] as $msg) { - echo "- " . $msg['prop'] . ': ' . $msg['explain'] . "\n"; - } - echo "Please fix your config files and run this script again!\n"; - echo "See ya.\n"; + // check file type detection + if ($RCI->check_mime_detection()) { + echo "WARNING: File type detection doesn't work properly!\n"; + echo "Please check the 'mime_magic' config option or the finfo functions of PHP and run this script again.\n"; } - } - - // check file type detection - if ($RCI->check_mime_detection()) { - echo "WARNING: File type detection doesn't work properly!\n"; - echo "Please check the 'mime_magic' config option or the finfo functions of PHP and run this script again.\n"; - } - if ($RCI->check_mime_extensions()) { - echo "WARNING: Mimetype to file extension mapping doesn't work properly!\n"; - echo "Please check the 'mime_types' config option and run this script again.\n"; - } - - // check database schema - if ($RCI->config['db_dsnw']) { - echo "Executing database schema update.\n"; - $success = rcmail_utils::db_update(INSTALL_PATH . 'SQL', 'roundcube', $opts['version'], - array('errors' => true)); - } - - // update composer dependencies - if (is_file(INSTALL_PATH . 'composer.json') && is_readable(INSTALL_PATH . 'composer.json-dist')) { - $composer_data = json_decode(file_get_contents(INSTALL_PATH . 'composer.json'), true); - $composer_template = json_decode(file_get_contents(INSTALL_PATH . 'composer.json-dist'), true); - $comsposer_json = null; - - // update the require section with the new dependencies - if (is_array($composer_data['require']) && is_array($composer_template['require'])) { - $composer_data['require'] = array_merge($composer_data['require'], $composer_template['require']); - - // remove obsolete packages - $old_packages = array( - 'pear-pear.php.net/net_socket', - 'pear-pear.php.net/auth_sasl', - 'pear-pear.php.net/net_idna2', - 'pear-pear.php.net/mail_mime', - 'pear-pear.php.net/net_smtp', - 'pear-pear.php.net/crypt_gpg', - 'pear-pear.php.net/net_sieve', - 'pear/mail_mime-decode', - 'roundcube/net_sieve', - 'endroid/qrcode', - ); - foreach ($old_packages as $pkg) { - if (array_key_exists($pkg, $composer_data['require'])) { - unset($composer_data['require'][$pkg]); - } - } + if ($RCI->check_mime_extensions()) { + echo "WARNING: Mimetype to file extension mapping doesn't work properly!\n"; + echo "Please check the 'mime_types' config option and run this script again.\n"; } - // update the repositories section with the new dependencies - if (is_array($composer_template['repositories'])) { - if (!is_array($composer_data['repositories'])) { - $composer_data['repositories'] = array(); - } - - foreach ($composer_template['repositories'] as $repo) { - $rkey = $repo['type'] . preg_replace('/^https?:/', '', $repo['url']) . $repo['package']['name']; - $existing = false; - foreach ($composer_data['repositories'] as $k => $_repo) { - if ($rkey == $_repo['type'] . preg_replace('/^https?:/', '', $_repo['url']) . $_repo['package']['name']) { - // switch to https:// - if (isset($_repo['url']) && strpos($_repo['url'], 'http://') === 0) - $composer_data['repositories'][$k]['url'] = 'https:' . substr($_repo['url'], 5); - $existing = true; - break; - } - // remove old repos - else if (strpos($_repo['url'], 'git://git.kolab.org') === 0) { - unset($composer_data['repositories'][$k]); - } - else if ($_repo['type'] == 'package' && $_repo['package']['name'] == 'Net_SMTP') { - unset($composer_data['repositories'][$k]); - } + // check database schema + if ($RCI->config['db_dsnw']) { + echo "Executing database schema update.\n"; + $success = rcmail_utils::db_update(INSTALL_PATH . 'SQL', 'roundcube', $opts['version'], + array('errors' => true)); + } + + // update composer dependencies + if (is_file(INSTALL_PATH . 'composer.json') && is_readable(INSTALL_PATH . 'composer.json-dist')) { + $composer_data = json_decode(file_get_contents(INSTALL_PATH . 'composer.json'), true); + $composer_template = json_decode(file_get_contents(INSTALL_PATH . 'composer.json-dist'), true); + $comsposer_json = null; + + // update the require section with the new dependencies + if (is_array($composer_data['require']) && is_array($composer_template['require'])) { + $composer_data['require'] = array_merge($composer_data['require'], $composer_template['require']); + + // remove obsolete packages + $old_packages = array( + 'pear-pear.php.net/net_socket', + 'pear-pear.php.net/auth_sasl', + 'pear-pear.php.net/net_idna2', + 'pear-pear.php.net/mail_mime', + 'pear-pear.php.net/net_smtp', + 'pear-pear.php.net/crypt_gpg', + 'pear-pear.php.net/net_sieve', + 'pear/mail_mime-decode', + 'roundcube/net_sieve', + 'endroid/qrcode', + ); + + foreach ($old_packages as $pkg) { + if (array_key_exists($pkg, $composer_data['require'])) { + unset($composer_data['require'][$pkg]); + } + } } - if (!$existing) { - $composer_data['repositories'][] = $repo; + + // update the repositories section with the new dependencies + if (is_array($composer_template['repositories'])) { + if (!is_array($composer_data['repositories'])) { + $composer_data['repositories'] = array(); + } + + foreach ($composer_template['repositories'] as $repo) { + $rkey = $repo['type'] . preg_replace('/^https?:/', '', $repo['url']) . $repo['package']['name']; + $existing = false; + + foreach ($composer_data['repositories'] as $k => $_repo) { + if ($rkey == $_repo['type'] . preg_replace('/^https?:/', '', $_repo['url']) . $_repo['package']['name']) { + // switch to https:// + if (isset($_repo['url']) && strpos($_repo['url'], 'http://') === 0) { + $composer_data['repositories'][$k]['url'] = 'https:' . substr($_repo['url'], 5); + } + + $existing = true; + break; + } + // remove old repos + if (strpos($_repo['url'], 'git://git.kolab.org') === 0) { + unset($composer_data['repositories'][$k]); + } + else if ($_repo['type'] == 'package' && $_repo['package']['name'] == 'Net_SMTP') { + unset($composer_data['repositories'][$k]); + } + } + + if (!$existing) { + $composer_data['repositories'][] = $repo; + } + } + + $composer_data['repositories'] = array_values($composer_data['repositories']); } - } - $composer_data['repositories'] = array_values($composer_data['repositories']); - } + // use the JSON encoder from the Composer package + if (is_file('composer.phar')) { + include 'phar://composer.phar/src/Composer/Json/JsonFile.php'; + $comsposer_json = \Composer\Json\JsonFile::encode($composer_data); + } + // PHP 5.4's json_encode() does the job, too + else if (defined('JSON_PRETTY_PRINT')) { + $comsposer_json = json_encode($composer_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); + } + else { + $success = false; + $comsposer_json = null; + } - // use the JSON encoder from the Composer package - if (is_file('composer.phar')) { - include 'phar://composer.phar/src/Composer/Json/JsonFile.php'; - $comsposer_json = \Composer\Json\JsonFile::encode($composer_data); - } - // PHP 5.4's json_encode() does the job, too - else if (defined('JSON_PRETTY_PRINT')) { - $comsposer_json = json_encode($composer_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); - } - else { - $success = false; - $comsposer_json = null; - } + // write updated composer.json back to disk + if ($comsposer_json && is_writeable(INSTALL_PATH . 'composer.json')) { + $success &= (bool)file_put_contents(INSTALL_PATH . 'composer.json', $comsposer_json); + } + else { + echo "WARNING: unable to update composer.json!\n"; + echo "Please replace the 'require' section in your composer.json with the following:\n"; - // write updated composer.json back to disk - if ($comsposer_json && is_writeable(INSTALL_PATH . 'composer.json')) { - $success &= (bool)file_put_contents(INSTALL_PATH . 'composer.json', $comsposer_json); - } - else { - echo "WARNING: unable to update composer.json!\n"; - echo "Please replace the 'require' section in your composer.json with the following:\n"; + $require_json = ''; + foreach ($composer_data['require'] as $pkg => $ver) { + $require_json .= sprintf(' "%s": "%s",'."\n", $pkg, $ver); + } - $require_json = ''; - foreach ($composer_data['require'] as $pkg => $ver) { - $require_json .= sprintf(' "%s": "%s",'."\n", $pkg, $ver); - } + echo ' "require": {'."\n"; + echo rtrim($require_json, ",\n"); + echo "\n }\n\n"; + } - echo ' "require": {'."\n"; - echo rtrim($require_json, ",\n"); - echo "\n }\n\n"; + echo "NOTE: Update dependencies by running `php composer.phar update --no-dev`\n"; } - echo "NOTE: Update dependencies by running `php composer.phar update --no-dev`\n"; - } - - // index contacts for fulltext searching - if ($opts['version'] && version_compare(version_parse($opts['version']), '0.6.0', '<')) { - rcmail_utils::indexcontacts(); - } + // index contacts for fulltext searching + if ($opts['version'] && version_compare(version_parse($opts['version']), '0.6.0', '<')) { + rcmail_utils::indexcontacts(); + } - if ($success) { - echo "This instance of Roundcube is up-to-date.\n"; - echo "Have fun!\n"; - } + if ($success) { + echo "This instance of Roundcube is up-to-date.\n"; + echo "Have fun!\n"; + } } else { - echo "This instance of Roundcube is not yet configured!\n"; - echo "Open http://url-to-roundcube/installer/ in your browser and follow the instuctions.\n"; + echo "This instance of Roundcube is not yet configured!\n"; + echo "Open http://url-to-roundcube/installer/ in your browser and follow the instuctions.\n"; }