Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 103 additions & 9 deletions features/package-install.feature
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
Feature: Install WP-CLI packages

Background:
When I run `wp package path`
Then save STDOUT as {PACKAGE_PATH}

Scenario: Install a package with an http package index url in package composer.json
Given an empty directory
And a composer.json file:
Expand Down Expand Up @@ -65,9 +69,6 @@ Feature: Install WP-CLI packages
Scenario: Install a package with a dependency
Given an empty directory

When I run `wp package path`
Then save STDOUT as {PACKAGE_PATH}

When I run `wp package install trendwerk/faker`
Then STDOUT should contain:
"""
Expand Down Expand Up @@ -123,9 +124,6 @@ Feature: Install WP-CLI packages
Scenario: Install a package from a Git URL
Given an empty directory

When I run `wp package path`
Then save STDOUT as {PACKAGE_PATH}

When I try `wp package install git@github.com:wp-cli.git`
Then STDERR should be:
"""
Expand All @@ -150,6 +148,105 @@ Feature: Install WP-CLI packages
| name |
| wp-cli/google-sitemap-generator-cli |

When I run `wp google-sitemap`
Then STDOUT should contain:
"""
usage: wp google-sitemap rebuild
"""

When I run `wp package uninstall wp-cli/google-sitemap-generator-cli`
Then STDOUT should contain:
"""
Removing require statement from {PACKAGE_PATH}composer.json
"""
And STDOUT should contain:
"""
Success: Uninstalled package.
"""

When I run `wp package list --fields=name`
Then STDOUT should not contain:
"""
wp-cli/google-sitemap-generator-cli
"""

Scenario: Install a package in a local zip
Given an empty directory
And I run `wget -O google-sitemap-generator-cli.zip https://github.com/wp-cli/google-sitemap-generator-cli/archive/master.zip`

When I run `wp package install google-sitemap-generator-cli.zip`
Then STDOUT should contain:
"""
Installing package wp-cli/google-sitemap-generator-cli (dev-master)
Updating {PACKAGE_PATH}composer.json to require the package...
Registering {PACKAGE_PATH}local/wp-cli-google-sitemap-generator-cli as a path repository...
Using Composer to install the package...
"""
And STDOUT should contain:
"""
Success: Package installed successfully.
"""

When I run `wp package list --fields=name`
Then STDOUT should be a table containing rows:
| name |
| wp-cli/google-sitemap-generator-cli |

When I run `wp google-sitemap`
Then STDOUT should contain:
"""
usage: wp google-sitemap rebuild
"""

When I run `wp package uninstall wp-cli/google-sitemap-generator-cli`
Then STDOUT should contain:
"""
Removing require statement from {PACKAGE_PATH}composer.json
"""
And STDOUT should contain:
"""
Success: Uninstalled package.
"""

When I run `wp package list --fields=name`
Then STDOUT should not contain:
"""
wp-cli/google-sitemap-generator-cli
"""

Scenario: Install a package from a remote ZIP
Given an empty directory

When I try `wp package install https://github.com/wp-cli/google-sitemap-generator.zip`
Then STDERR should be:
"""
Error: Couldn't download package.
"""

When I run `wp package install https://github.com/wp-cli/google-sitemap-generator-cli/archive/master.zip`
Then STDOUT should contain:
"""
Installing package wp-cli/google-sitemap-generator-cli (dev-master)
Updating {PACKAGE_PATH}composer.json to require the package...
Registering {PACKAGE_PATH}local/wp-cli-google-sitemap-generator-cli as a path repository...
Using Composer to install the package...
"""
And STDOUT should contain:
"""
Success: Package installed successfully.
"""

When I run `wp package list --fields=name`
Then STDOUT should be a table containing rows:
| name |
| wp-cli/google-sitemap-generator-cli |

When I run `wp google-sitemap`
Then STDOUT should contain:
"""
usage: wp google-sitemap rebuild
"""

When I run `wp package uninstall wp-cli/google-sitemap-generator-cli`
Then STDOUT should contain:
"""
Expand Down Expand Up @@ -193,9 +290,6 @@ Feature: Install WP-CLI packages
}
"""

When I run `wp package path`
Then save STDOUT as {PACKAGE_PATH}

When I run `pwd`
Then save STDOUT as {CURRENT_PATH}

Expand Down
138 changes: 138 additions & 0 deletions php/WP_CLI/Extractor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<?php

namespace WP_CLI;

use Exception;
use PharData;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use WP_CLI;
use WP_CLI\Utils;
use ZipArchive;

/**
* Extract a provided archive file.
*/
class Extractor {

/**
* Extract the archive file to a specific destination.
*
* @param string $dest
*/
public static function extract( $tarball_or_zip, $dest ) {
if ( preg_match( '/\.zip$/', $tarball_or_zip ) ) {
return self::extract_zip( $tarball_or_zip, $dest );
}

if ( preg_match( '/\.tar\.gz$/', $tarball_or_zip ) ) {
return self::extract_tarball( $tarball_or_zip, $dest );
}
throw new \Exception( 'Extension not supported.' );
}

/**
* Extract a ZIP file to a specific destination.
*
* @param string $zipfile
* @param string $dest
*/
private static function extract_zip( $zipfile, $dest ) {
if ( ! class_exists( 'ZipArchive' ) ) {
throw new Exception( 'Extracting a zip file requires ZipArchive.' );
}
$zip = new ZipArchive();
$res = $zip->open( $zipfile );
if ( true === $res ) {
$tempdir = implode( DIRECTORY_SEPARATOR, Array (
dirname( $zipfile ),
basename( $zipfile, '.zip' ),
$zip->getNameIndex( 0 )
) );

$zip->extractTo( dirname( $tempdir ) );
$zip->close();

self::copy_overwrite_files( $tempdir, $dest );
self::rmdir( dirname( $tempdir ) );
} else {
throw Exception( $res );
}
}

/**
* Extract a tarball to a specific destination.
*
* @param string $tarball
* @param string $dest
*/
private static function extract_tarball( $tarball, $dest ) {
if ( ! class_exists( 'PharData' ) ) {
$cmd = "tar xz --strip-components=1 --directory=%s -f $tarball";
WP_CLI::launch( Utils\esc_cmd( $cmd, $dest ) );
return;
}
$phar = new PharData( $tarball );
$tempdir = implode( DIRECTORY_SEPARATOR, Array (
dirname( $tarball ),
basename( $tarball, '.tar.gz' ),
$phar->getFileName()
) );

$phar->extractTo( dirname( $tempdir ), null, true );

self::copy_overwrite_files( $tempdir, $dest );

self::rmdir( dirname( $tempdir ) );
}

public static function copy_overwrite_files( $source, $dest ) {
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator( $source, RecursiveDirectoryIterator::SKIP_DOTS ),
RecursiveIteratorIterator::SELF_FIRST);

$error = 0;

if ( ! is_dir( $dest ) ) {
mkdir( $dest, 0777, true );
}

foreach ( $iterator as $item ) {

$dest_path = $dest . DIRECTORY_SEPARATOR . $iterator->getSubPathName();

if ( $item->isDir() ) {
if ( !is_dir( $dest_path ) ) {
mkdir( $dest_path );
}
} else {
if ( file_exists( $dest_path ) && is_writable( $dest_path ) ) {
copy( $item, $dest_path );
} elseif ( ! file_exists( $dest_path ) ) {
copy( $item, $dest_path );
} else {
$error = 1;
WP_CLI::warning( "Unable to copy '" . $iterator->getSubPathName() . "' to current directory." );
}
}
}

if ( $error ) {
throw new Exception( 'There was an error overwriting existing files.' );
}
}

public static function rmdir( $dir ) {
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator( $dir, RecursiveDirectoryIterator::SKIP_DOTS ),
RecursiveIteratorIterator::CHILD_FIRST
);

foreach ( $files as $fileinfo ) {
$todo = $fileinfo->isDir() ? 'rmdir' : 'unlink';
$todo( $fileinfo->getRealPath() );
}
rmdir( $dir );
}

}
Loading