Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / vendor / consolidation / robo / src / Task / Archive / Pack.php
1 <?php
2
3 namespace Robo\Task\Archive;
4
5 use Robo\Contract\PrintedInterface;
6 use Robo\Result;
7 use Robo\Task\BaseTask;
8 use Symfony\Component\Finder\Finder;
9
10 /**
11  * Creates a zip or tar archive.
12  *
13  * ``` php
14  * <?php
15  * $this->taskPack(
16  * <archiveFile>)
17  * ->add('README')                         // Puts file 'README' in archive at the root
18  * ->add('project')                        // Puts entire contents of directory 'project' in archinve inside 'project'
19  * ->addFile('dir/file.txt', 'file.txt')   // Takes 'file.txt' from cwd and puts it in archive inside 'dir'.
20  * ->run();
21  * ?>
22  * ```
23  */
24 class Pack extends BaseTask implements PrintedInterface
25 {
26     /**
27      * The list of items to be packed into the archive.
28      *
29      * @var array
30      */
31     private $items = [];
32
33     /**
34      * The full path to the archive to be created.
35      *
36      * @var string
37      */
38     private $archiveFile;
39
40     /**
41      * Construct the class.
42      *
43      * @param string $archiveFile The full path and name of the archive file to create.
44      *
45      * @since   1.0
46      */
47     public function __construct($archiveFile)
48     {
49         $this->archiveFile = $archiveFile;
50     }
51
52     /**
53      * Satisfy the parent requirement.
54      *
55      * @return bool Always returns true.
56      *
57      * @since   1.0
58      */
59     public function getPrinted()
60     {
61         return true;
62     }
63
64     /**
65      * @param string $archiveFile
66      *
67      * @return $this
68      */
69     public function archiveFile($archiveFile)
70     {
71         $this->archiveFile = $archiveFile;
72         return $this;
73     }
74
75     /**
76      * Add an item to the archive. Like file_exists(), the parameter
77      * may be a file or a directory.
78      *
79      * @var string
80      *             Relative path and name of item to store in archive
81      * @var string
82      *             Absolute or relative path to file or directory's location in filesystem
83      *
84      * @return $this
85      */
86     public function addFile($placementLocation, $filesystemLocation)
87     {
88         $this->items[$placementLocation] = $filesystemLocation;
89
90         return $this;
91     }
92
93     /**
94      * Alias for addFile, in case anyone has angst about using
95      * addFile with a directory.
96      *
97      * @var string
98      *             Relative path and name of directory to store in archive
99      * @var string
100      *             Absolute or relative path to directory or directory's location in filesystem
101      *
102      * @return $this
103      */
104     public function addDir($placementLocation, $filesystemLocation)
105     {
106         $this->addFile($placementLocation, $filesystemLocation);
107
108         return $this;
109     }
110
111     /**
112      * Add a file or directory, or list of same to the archive.
113      *
114      * @var string|array
115      *                   If given a string, should contain the relative filesystem path to the
116      *                   the item to store in archive; this will also be used as the item's
117      *                   path in the archive, so absolute paths should not be used here.
118      *                   If given an array, the key of each item should be the path to store
119      *                   in the archive, and the value should be the filesystem path to the
120      *                   item to store.
121      * @return $this
122      */
123     public function add($item)
124     {
125         if (is_array($item)) {
126             $this->items = array_merge($this->items, $item);
127         } else {
128             $this->addFile($item, $item);
129         }
130
131         return $this;
132     }
133
134     /**
135      * Create a zip archive for distribution.
136      *
137      * @return \Robo\Result
138      *
139      * @since  1.0
140      */
141     public function run()
142     {
143         $this->startTimer();
144
145         // Use the file extension to determine what kind of archive to create.
146         $fileInfo = new \SplFileInfo($this->archiveFile);
147         $extension = strtolower($fileInfo->getExtension());
148         if (empty($extension)) {
149             return Result::error($this, "Archive filename must use an extension (e.g. '.zip') to specify the kind of archive to create.");
150         }
151
152         try {
153             // Inform the user which archive we are creating
154             $this->printTaskInfo("Creating archive {filename}", ['filename' => $this->archiveFile]);
155             if ($extension == 'zip') {
156                 $result = $this->archiveZip($this->archiveFile, $this->items);
157             } else {
158                 $result = $this->archiveTar($this->archiveFile, $this->items);
159             }
160             $this->printTaskSuccess("{filename} created.", ['filename' => $this->archiveFile]);
161         } catch (\Exception $e) {
162             $this->printTaskError("Could not create {filename}. {exception}", ['filename' => $this->archiveFile, 'exception' => $e->getMessage(), '_style' => ['exception' => '']]);
163             $result = Result::error($this, sprintf('Could not create %s. %s', $this->archiveFile, $e->getMessage()));
164         }
165         $this->stopTimer();
166         $result['time'] = $this->getExecutionTime();
167
168         return $result;
169     }
170
171     /**
172      * @param string $archiveFile
173      * @param array $items
174      *
175      * @return \Robo\Result
176      */
177     protected function archiveTar($archiveFile, $items)
178     {
179         if (!class_exists('Archive_Tar')) {
180             return Result::errorMissingPackage($this, 'Archive_Tar', 'pear/archive_tar');
181         }
182
183         $tar_object = new \Archive_Tar($archiveFile);
184         foreach ($items as $placementLocation => $filesystemLocation) {
185             $p_remove_dir = $filesystemLocation;
186             $p_add_dir = $placementLocation;
187             if (is_file($filesystemLocation)) {
188                 $p_remove_dir = dirname($filesystemLocation);
189                 $p_add_dir = dirname($placementLocation);
190                 if (basename($filesystemLocation) != basename($placementLocation)) {
191                     return Result::error($this, "Tar archiver does not support renaming files during extraction; could not add $filesystemLocation as $placementLocation.");
192                 }
193             }
194
195             if (!$tar_object->addModify([$filesystemLocation], $p_add_dir, $p_remove_dir)) {
196                 return Result::error($this, "Could not add $filesystemLocation to the archive.");
197             }
198         }
199
200         return Result::success($this);
201     }
202
203     /**
204      * @param string $archiveFile
205      * @param array $items
206      *
207      * @return \Robo\Result
208      */
209     protected function archiveZip($archiveFile, $items)
210     {
211         if (!extension_loaded('zlib')) {
212             return Result::errorMissingExtension($this, 'zlib', 'zip packing');
213         }
214
215         $zip = new \ZipArchive($archiveFile, \ZipArchive::CREATE);
216         if (!$zip->open($archiveFile, \ZipArchive::CREATE)) {
217             return Result::error($this, "Could not create zip archive {$archiveFile}");
218         }
219         $result = $this->addItemsToZip($zip, $items);
220         $zip->close();
221
222         return $result;
223     }
224
225     /**
226      * @param \ZipArchive $zip
227      * @param array $items
228      *
229      * @return \Robo\Result
230      */
231     protected function addItemsToZip($zip, $items)
232     {
233         foreach ($items as $placementLocation => $filesystemLocation) {
234             if (is_dir($filesystemLocation)) {
235                 $finder = new Finder();
236                 $finder->files()->in($filesystemLocation)->ignoreDotFiles(false);
237
238                 foreach ($finder as $file) {
239                     // Replace Windows slashes or resulting zip will have issues on *nixes.
240                     $relativePathname = str_replace('\\', '/', $file->getRelativePathname());
241
242                     if (!$zip->addFile($file->getRealpath(), "{$placementLocation}/{$relativePathname}")) {
243                         return Result::error($this, "Could not add directory $filesystemLocation to the archive; error adding {$file->getRealpath()}.");
244                     }
245                 }
246             } elseif (is_file($filesystemLocation)) {
247                 if (!$zip->addFile($filesystemLocation, $placementLocation)) {
248                     return Result::error($this, "Could not add file $filesystemLocation to the archive.");
249                 }
250             } else {
251                 return Result::error($this, "Could not find $filesystemLocation for the archive.");
252             }
253         }
254
255         return Result::success($this);
256     }
257 }