Skip to content

Commit

Permalink
GitDirectoryResource: Accept "/", "", "." as root paths (#1860)
Browse files Browse the repository at this point in the history
GitDirectoryResource was merged in
#1858.
Unfortunately, it didn't provide an easy way of saying "checkout all the
files from the repo". This PR adds support for three root path syntaxes:

* `"path": "/"`
* `"path": "."`
* `"path": ""`

 ## Testing instructions

Run this Blueprint locally and confirm it installs the blocky formats
plugin:

```json
{
	"$schema": "https://playground.wordpress.net/blueprint-schema.json",
	"login": true,
	"landingPage": "/wp-admin/",
    "steps": [
        {
            "step": "installPlugin",
            "pluginData": {
                "resource": "git:directory",
                "url": "https://github.com/dmsnell/blocky-formats.git",
                "ref": "trunk",
                "path": "/"
            }
        }
    ]
}
```
  • Loading branch information
adamziel authored Oct 8, 2024
1 parent 70a6c2c commit 1732f77
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 20 deletions.
8 changes: 6 additions & 2 deletions packages/playground/blueprints/src/lib/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -461,9 +461,13 @@ export class GitDirectoryResource extends Resource<Directory> {
const repoUrl = this.options?.corsProxy
? `${this.options.corsProxy}/${this.reference.url}`
: this.reference.url;
const ref = `refs/heads/${this.reference.ref}`;
const ref = ['', 'HEAD'].includes(this.reference.ref)
? 'HEAD'
: `refs/heads/${this.reference.ref}`;
const allFiles = await listGitFiles(repoUrl, ref);
const filesToClone = listDescendantFiles(allFiles, this.reference.path);

const requestedPath = this.reference.path.replace(/^\/+/, '');
const filesToClone = listDescendantFiles(allFiles, requestedPath);
let files = await sparseCheckout(repoUrl, ref, filesToClone);
// Remove the path prefix from the cloned file names.
files = Object.fromEntries(
Expand Down
122 changes: 122 additions & 0 deletions packages/playground/storage/src/lib/paths.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { FileTree } from './git-sparse-checkout';
import { listDescendantFiles } from './paths';

const testTree: FileTree[] = [
{
name: 'packages',
type: 'folder',
children: [
{
name: 'playground',
type: 'folder',
children: [
{
name: 'storage',
type: 'folder',
children: [
{
name: 'package.json',
type: 'file',
},
{
name: 'STORAGE_README.md',
type: 'file',
},
],
},
],
},
{
name: 'php-wasm',
type: 'folder',
children: [
{
name: 'package.json',
type: 'file',
},
],
},
],
},
{
name: 'wordpress',
type: 'folder',
children: [
{
name: 'wp-content',
type: 'folder',
children: [
{
name: 'plugins',
type: 'folder',
children: [
{
name: 'blocky-formats',
type: 'folder',
children: [
{
name: 'block.json',
type: 'file',
},
{
name: 'index.php',
type: 'file',
},
{
name: 'README.md',
type: 'file',
},
],
},
],
},
],
},
{
name: 'index.php',
type: 'file',
},
{
name: 'wp-includes',
type: 'folder',
children: [
{
name: 'version.php',
type: 'file',
},
],
},
{
name: 'wp-config.php',
type: 'file',
},
],
},
];

describe('listDescendantFiles', () => {
it('should list all the descendant files from a subdirectory of a file tree', async () => {
const files = listDescendantFiles(testTree, 'packages/playground');
expect(files).toEqual(
expect.arrayContaining([
'packages/playground/storage/package.json',
'packages/playground/storage/STORAGE_README.md',
])
);
});
it.each(['.', '/', ''])(
'should list all the descendant files when "%s" is passed as path',
async (path: string) => {
const files = listDescendantFiles(
[
{
name: 'index.php',
type: 'file',
},
],
path
);
expect(files).toEqual(expect.arrayContaining(['index.php']));
}
);
});
41 changes: 23 additions & 18 deletions packages/playground/storage/src/lib/paths.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,46 @@
import { normalizePath } from '@php-wasm/util';
import { FileTree } from './git-sparse-checkout';

export function listDescendantFiles(files: FileTree[], selectedPath: string) {
if (!selectedPath) {
return [];
}
selectedPath = normalizePath(selectedPath);
const isRoot = ['', '.', '/'].includes(selectedPath);

// Calculate the list of files to checkout based on the mapping
const descendants: string[] = [];
const segments = selectedPath.split('/');
let currentTree: FileTree[] | null = files;
for (const segment of segments) {
const file = currentTree?.find(
(file) => file.name === segment
) as FileTree;
if (file?.type === 'folder') {
currentTree = file.children;
} else if (file) {
return [file.name];
} else {
return [];
if (isRoot) {
selectedPath = '';
} else {
const segments = selectedPath.split('/');
for (const segment of segments) {
const file = currentTree?.find(
(file) => file.name === segment
) as FileTree;
if (file?.type === 'folder') {
currentTree = file.children;
} else if (file) {
return [file.name];
} else {
return [];
}
}
}

// Calculate the list of files to checkout based on the mapping
const descendants: string[] = [];
const stack = [{ tree: currentTree, path: selectedPath }];
while (stack.length > 0) {
const { tree, path } = stack.pop() as {
tree: FileTree[];
path: string;
};
for (const file of tree) {
const filePath = `${path}${path ? '/' : ''}${file.name}`;
if (file.type === 'folder') {
stack.push({
tree: file.children,
path: `${path}/${file.name}`,
path: filePath,
});
} else {
descendants.push(`${path}/${file.name}`);
descendants.push(filePath);
}
}
}
Expand Down

0 comments on commit 1732f77

Please sign in to comment.