getkirby / cli

Kirby Command Line Interface
MIT License
51 stars 5 forks source link

unzip command looses top level dotfiles (.htaccess, .gitignore, etc...) #19

Closed rasteiner closed 1 year ago

rasteiner commented 1 year ago

When using kirby install:kit plainkit, the resulting folder does not contain .htaccess. This is on Linux with bash, don't know about mac stuff. The resulting installation therefore doesn't work.

I suspect these lines in unzip.php to be the culprit:

// move everything one level up
exec('mv ' . $to . '/*/* ' . $to);

In bash, from/folder/* is expanded only to visible files and folders in from/folder. The hidden files are therefore left in the $archive folder and then deleted together with it.

replacing the above mentioned lines with something that doesn't rely on glob expansion seems to be the most straight forward:

// move everything one level up (including hidden files)
foreach(new DirectoryIterator($archive) as $item) {
    if ($item->isDot() === true) {
        // skip dots (.. and .)
        continue;
    }

    rename($item->getPathname(), $to . '/' . $item->getBasename());
}

another approach would be to extract the archive to the system temp directory and then simply move the whole folder (instead of its files) to the $to path:

    'command' => static function (CLI $cli): void {
        $file = $cli->arg('file');
        $to   = $cli->arg('to');

        if (is_file($file) === false) {
            throw new Exception('The ZIP file does not exist');
        }

        if (is_dir($to) === true) {
            throw new Exception('The target directory exists');
        }

        // get a temporary directory
        $tmp = sys_get_temp_dir() . '/' . uniqid('kirby-cli-', true);

        // extract the zip file
        exec('unzip ' . $file . ' -d ' . $tmp);

        // find the archive folder in that tmp dir
        $archive = glob($tmp . '/*', GLOB_ONLYDIR)[0] ?? null;

        if (is_dir($archive) === false) {
            throw new Exception('The archive directory could not be found');
        }

        // move archive to destination
        rename($archive, $to);

        // remove the (now empty) temporary directory
        rmdir($tmp);
    }
bastianallgeier commented 1 year ago

I already fixed this on the develop branch.