Skip to content

Commit ee6ccc3

Browse files
committed
Complete first pass on Manifests
1 parent 9ee3930 commit ee6ccc3

File tree

13 files changed

+141
-22
lines changed

13 files changed

+141
-22
lines changed

bin/Assets.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ class Assets extends \Tatter\Assets\Config\Assets
2525
// Location of asset URLs
2626
public $webBase = 'https://example.com/assets/';
2727

28+
// Starting directory for manifest publication
29+
public $publishRoot = ROOTPATH;
30+
2831
// Additional paths to load per route
2932
// Relative to fileBase, no leading/trailing slashes
3033
public $routes = [

src/Config/Assets.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ class Assets extends BaseConfig
1616
// Location of asset URLs
1717
public $webBase = 'assets/';
1818

19+
// Starting directory for manifest publication
20+
public $publishRoot = ROOTPATH;
21+
1922
// Additional paths to load per route
2023
// Relative to fileBase, no leading/trailing slashes
2124
public $routes = [];

src/Libraries/Manifests.php

Lines changed: 133 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ public function publish($path): bool
6565
$result = true;
6666
foreach ($manifest->resources as $resource)
6767
{
68+
$this->expandPaths($resource, $manifest);
6869
$result = $result && $this->publishResource($resource);
6970
}
7071

@@ -81,8 +82,11 @@ protected function manifestFromFile($path): ?object
8182
{
8283
if ($this->config->silent)
8384
{
84-
log_message('warning', lang('Files.fileNotFound', [$path]));
85-
return;
85+
$error = lang('Files.fileNotFound', [$path]);
86+
log_message('warning', $error);
87+
$this->messages[] = [$error, 'red'];
88+
89+
return null;
8690
}
8791

8892
throw FileNotFoundException::forFileNotFound($path);
@@ -98,9 +102,9 @@ protected function manifestFromFile($path): ?object
98102
if ($this->config->silent)
99103
{
100104
$error = 'JSON Error #' . $errornum . '. ' . lang('Manifests.invalidFileFormat', [$path]);
101-
log_message('warning', $error));
105+
log_message('warning', $error);
102106
$this->messages[] = [$error, 'red'];
103-
return;
107+
return null;
104108
}
105109

106110
throw ManifestsException::forInvalidFileFormat($path);
@@ -114,9 +118,9 @@ protected function manifestFromFile($path): ?object
114118
if ($this->config->silent)
115119
{
116120
$error = lang('Manifests.fieldMissingFromFile', [$field, $path]);
117-
log_message('warning', $error));
121+
log_message('warning', $error);
118122
$this->messages[] = [$error, 'red'];
119-
return;
123+
return null;
120124
}
121125

122126
throw ManifestsException::forFieldMissingFromFile($field, $path);
@@ -158,6 +162,7 @@ protected function secureDestination($path): bool
158162

159163
// Make sure a directory exists and is writable
160164
protected function ensureDirectory($directory): bool
165+
{
161166
// Check for existence
162167
if (! file_exists($directory))
163168
{
@@ -168,7 +173,7 @@ protected function ensureDirectory($directory): bool
168173
if (! is_dir($directory))
169174
{
170175
$error = lang('Manifests.cannotCreateDirectory', [$directory]);
171-
log_message('warning', $error));
176+
log_message('warning', $error);
172177
$this->messages[] = [$error, 'red'];
173178
return false;
174179
}
@@ -177,7 +182,7 @@ protected function ensureDirectory($directory): bool
177182
if (! is_writable($directory))
178183
{
179184
$error = lang('Manifests.directoryNotWritable', [$directory]);
180-
log_message('warning', $error));
185+
log_message('warning', $error);
181186
$this->messages[] = [$error, 'red'];
182187
return false;
183188
}
@@ -197,11 +202,11 @@ protected function addIndexToDirectory($directory): bool
197202
return true;
198203
}
199204

200-
// Directory should be writable but jsut in case...
205+
// Directory should be writable but just in case...
201206
if (! $file->isWritable)
202207
{
203208
$error = lang('Manifests.directoryNotWritable', [$directory]);
204-
log_message('warning', $error));
209+
log_message('warning', $error);
205210
$this->messages[] = [$error, 'red'];
206211
return false;
207212
}
@@ -211,7 +216,7 @@ protected function addIndexToDirectory($directory): bool
211216
if (! $file->fwrite($this->getIndexHtml))
212217
{
213218
$error = lang('Manifests.cannotCreateIndexFile', [$path]);
214-
log_message('warning', $error));
219+
log_message('warning', $error);
215220
$this->messages[] = [$error, 'red'];
216221
return false;
217222
}
@@ -235,9 +240,23 @@ protected function getIndexHtml(): string
235240
</html>
236241
';
237242
}
243+
244+
// Expand resource paths relative to the configured publish root and the manifest property
245+
protected function expandPaths(&$resource, &$manifest)
246+
{
247+
$resource->source =
248+
rtrim($this->config->publishRoot, '/') . '/' .
249+
trim($manifest->source, '/') . '/' .
250+
ltrim($resource->source, '/');
251+
252+
$resource->destination =
253+
rtrim($this->config->publishRoot, '/') . '/' .
254+
trim($manifest->destination, '/') . '/' .
255+
ltrim($resource->destination ?? '', '/');
256+
}
238257

239258
// Parse a resource and copy it to the determined destination
240-
protected function publishResource($resource): ?object
259+
protected function publishResource($resource): bool
241260
{
242261
// Validate the source
243262
if (! isset($resource->source))
@@ -247,7 +266,108 @@ protected function publishResource($resource): ?object
247266

248267
// Make sure the source exists
249268
$file = new File($resource->source);
250-
//WIP
269+
if (! $file->getRealPath())
270+
{
271+
if ($this->config->silent)
272+
{
273+
$error = lang('Files.fileNotFound', [$path]);
274+
log_message('warning', $error);
275+
$this->messages[] = [$error, 'red'];
276+
277+
return false;
278+
}
279+
280+
throw FileNotFoundException::forFileNotFound($path);
281+
}
282+
283+
return $file->isDir() ?
284+
$this->publishResourceDirectory($resource) :
285+
$this->publishFile($resource->source, $resource->destination);
286+
}
287+
288+
// Scan a directory and apply filters, publishing each file
289+
protected function publishResourceDirectory($resource): bool
290+
{
291+
$result = true;
292+
293+
// Recursive, flatten
294+
if (! empty($resource->recursive) && ! empty($resource->flatten))
295+
{
296+
$files = get_filenames($resource->source, true);
297+
if (! empty($resource->filter))
298+
{
299+
$files = preg_grep($resource->filter, $files);
300+
}
301+
302+
// Publish every file back to the destination
303+
foreach ($files as $file)
304+
{
305+
$result = $this->publishFile($file, $resource->destination);
306+
}
307+
308+
return $result;
309+
}
310+
311+
// Recursive, not flatten
312+
elseif (! empty($resource->recursive))
313+
{
314+
$items = directory_map($resource->source);
315+
return $this->publishDirectoryRecursive($items, $resource->source, $resource->destination);
316+
}
317+
318+
// Publish every file back to the destination
319+
foreach ($files as $source => $destination)
320+
{
321+
$result = $this->publishFile($source, $destination);
322+
}
323+
324+
return $result;
325+
}
326+
327+
// Recursive-safe directory publish
328+
protected function publishDirectoryRecursive(array $items, string $source, string $destination): bool
329+
{
330+
$result = true;
331+
332+
foreach ($items as $dir => $item)
333+
{
334+
// Directory
335+
if (is_array($item))
336+
{
337+
$result = $result && $this->publishDirectoryRecursive($item, $source . $dir, $destination . $dir);
338+
}
339+
// File
340+
else
341+
{
342+
$result = $result && $this->publishFile($source . $item, $destination);
343+
}
344+
}
345+
346+
return $result;
347+
}
251348

349+
// Copy a file into place, creating and securing missing directories
350+
protected function publishFile(string $source, string $destination): bool
351+
{
352+
if (! $this->secureDestination($destination))
353+
{
354+
return false;
355+
}
356+
357+
if (copy($source, $destination))
358+
{
359+
return true;
360+
}
361+
362+
if ($this->config->silent)
363+
{
364+
$error = lang('Files.cannotMove', [$source, $destination, -1]);
365+
log_message('warning', $error);
366+
$this->messages[] = [$error, 'red'];
367+
368+
return false;
369+
}
370+
371+
throw FileException::forUnableToMove($source, $destination, -1);
252372
}
253373
}

tests/_support/Manifests/LawyerPack.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"source": "WidgetModule/dist",
2+
"source": "vendor/lawyerpack/dist",
33
"destination": "vendor/widgets",
44
"resources": [
55
{

tests/_support/Manifests/Widgets.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"source": "WidgetModule/dist",
2+
"source": "vendor/WidgetModule/dist",
33
"destination": "vendor/widgets",
44
"resources": [
55
{

tests/_support/WidgetModule/dist/notAsset.json

Lines changed: 0 additions & 3 deletions
This file was deleted.

tests/_support/WidgetModule/dist/widget_scripts.js

Lines changed: 0 additions & 1 deletion
This file was deleted.

tests/_support/WidgetModule/dist/widget_style.css

Lines changed: 0 additions & 3 deletions
This file was deleted.

tests/_support/lawyerpack/file1.css

Whitespace-only changes.

tests/_support/lawyerpack/file2.css

Whitespace-only changes.

0 commit comments

Comments
 (0)