From a365f1faf4dbb262062775e3d000dd93c5851235 Mon Sep 17 00:00:00 2001 From: Bartosz Nadworny Date: Wed, 25 Aug 2021 14:30:40 +0200 Subject: [PATCH 1/4] Disable default stripping of ZIP archive Signed-off-by: Bartosz Nadworny --- .changeset/angry-planes-visit.md | 5 +++++ .../backend-common/src/reading/tree/ZipArchiveResponse.ts | 7 ++++--- 2 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 .changeset/angry-planes-visit.md diff --git a/.changeset/angry-planes-visit.md b/.changeset/angry-planes-visit.md new file mode 100644 index 0000000000..622a7750f9 --- /dev/null +++ b/.changeset/angry-planes-visit.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +Disable stripping of ZIP archive diff --git a/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts b/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts index 5c12a383ee..c40557ce94 100644 --- a/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts +++ b/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts @@ -38,6 +38,7 @@ export class ZipArchiveResponse implements ReadTreeResponse { private readonly workDir: string, public readonly etag: string, private readonly filter?: (path: string, info: { size: number }) => boolean, + private readonly stripFirstDirectoryFromPath?: boolean, ) { if (subPath) { if (!subPath.endsWith('/')) { @@ -67,7 +68,7 @@ export class ZipArchiveResponse implements ReadTreeResponse { } private shouldBeIncluded(entry: Entry): boolean { - const strippedPath = stripFirstDirectoryFromPath(entry.path); + const strippedPath = this.stripFirstDirectoryFromPath ? stripFirstDirectoryFromPath(entry.path) : entry.path; if (this.subPath) { if (!strippedPath.startsWith(this.subPath)) { @@ -99,7 +100,7 @@ export class ZipArchiveResponse implements ReadTreeResponse { if (this.shouldBeIncluded(entry)) { files.push({ - path: this.getInnerPath(stripFirstDirectoryFromPath(entry.path)), + path: this.getInnerPath(this.stripFirstDirectoryFromPath ? stripFirstDirectoryFromPath(entry.path) : entry.path), content: () => entry.buffer(), }); } else { @@ -148,7 +149,7 @@ export class ZipArchiveResponse implements ReadTreeResponse { // as a zip can have files with directories without directory entries if (entry.type === 'File' && this.shouldBeIncluded(entry)) { const entryPath = this.getInnerPath( - stripFirstDirectoryFromPath(entry.path), + this.stripFirstDirectoryFromPath ? stripFirstDirectoryFromPath(entry.path) : entry.path, ); const dirname = platformPath.dirname(entryPath); if (dirname) { From b1e6334a313a4aca9e83f079937975e1d8c846d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Thu, 26 Aug 2021 11:15:07 +0200 Subject: [PATCH 2/4] review fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .changeset/angry-planes-visit.md | 4 ++-- .../src/reading/tree/ZipArchiveResponse.ts | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/.changeset/angry-planes-visit.md b/.changeset/angry-planes-visit.md index 622a7750f9..5c0a78f0c7 100644 --- a/.changeset/angry-planes-visit.md +++ b/.changeset/angry-planes-visit.md @@ -1,5 +1,5 @@ --- -'@backstage/backend-common': patch +'@backstage/backend-common': minor --- -Disable stripping of ZIP archive +The `ZipArchiveResponse` class now accepts an optional `stripFirstDirectory` parameter. Note that its default value is `false`, which leads to a breaking change in behaviour to previous versions of the class. If you use this class explicitly and want to retain the old behaviour, add a `true` parameter value to its constructor. diff --git a/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts b/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts index c40557ce94..fb22f24b94 100644 --- a/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts +++ b/packages/backend-common/src/reading/tree/ZipArchiveResponse.ts @@ -38,7 +38,7 @@ export class ZipArchiveResponse implements ReadTreeResponse { private readonly workDir: string, public readonly etag: string, private readonly filter?: (path: string, info: { size: number }) => boolean, - private readonly stripFirstDirectoryFromPath?: boolean, + private readonly stripFirstDirectory?: boolean, ) { if (subPath) { if (!subPath.endsWith('/')) { @@ -68,7 +68,9 @@ export class ZipArchiveResponse implements ReadTreeResponse { } private shouldBeIncluded(entry: Entry): boolean { - const strippedPath = this.stripFirstDirectoryFromPath ? stripFirstDirectoryFromPath(entry.path) : entry.path; + const strippedPath = this.stripFirstDirectory + ? stripFirstDirectoryFromPath(entry.path) + : entry.path; if (this.subPath) { if (!strippedPath.startsWith(this.subPath)) { @@ -100,7 +102,11 @@ export class ZipArchiveResponse implements ReadTreeResponse { if (this.shouldBeIncluded(entry)) { files.push({ - path: this.getInnerPath(this.stripFirstDirectoryFromPath ? stripFirstDirectoryFromPath(entry.path) : entry.path), + path: this.getInnerPath( + this.stripFirstDirectory + ? stripFirstDirectoryFromPath(entry.path) + : entry.path, + ), content: () => entry.buffer(), }); } else { @@ -149,7 +155,9 @@ export class ZipArchiveResponse implements ReadTreeResponse { // as a zip can have files with directories without directory entries if (entry.type === 'File' && this.shouldBeIncluded(entry)) { const entryPath = this.getInnerPath( - this.stripFirstDirectoryFromPath ? stripFirstDirectoryFromPath(entry.path) : entry.path, + this.stripFirstDirectory + ? stripFirstDirectoryFromPath(entry.path) + : entry.path, ); const dirname = platformPath.dirname(entryPath); if (dirname) { From 63e4f030525edec3c03d00ab822eb965bd1a6600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Thu, 26 Aug 2021 11:30:02 +0200 Subject: [PATCH 3/4] update test fixture files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .../src/reading/__fixtures__/mock-main.zip | Bin 777 -> 485 bytes .../__fixtures__/mock-with-extra-root-dir.zip | Bin 0 -> 777 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 packages/backend-common/src/reading/__fixtures__/mock-with-extra-root-dir.zip diff --git a/packages/backend-common/src/reading/__fixtures__/mock-main.zip b/packages/backend-common/src/reading/__fixtures__/mock-main.zip index beee59d3a075b3e439f5eb436051afae2fdb15f1..ae362448fc75a7b1123fe459c28cd96933c927ba 100644 GIT binary patch literal 485 zcmWIWW@h1H0D%p)(Scvv-s}?qvO$=OL53kWJ0(B4Sg$fSCp3hUfw|jgM*Q^{^~BN& zZU#n{uZ#=~EFwUa#hE3k@p*~4sa6Uhsl_E+0dOR9h1H`7qcFXS?6k=+qYxek8VT|^hU-|_ QK>lC`!goOWA&A2O0LVOBG5`Po literal 777 zcmWIWW@Zs#0D;aZ!yqsNN^mhKFy!VZXY1xBX6EUKhVU}5C-bu;fN&NNmsW5yFtU7Q zWMBa64*;9P!N9?=zBW1#W{v=mA%bE~Zgxt3a`hUFdG-N3j!RBdQ0mScmYyHY5+Q z0}U6)G%PbOCAC5?HwEm689+b4LI%wb!C^>FpC)oXf)i*S$jkt5MkWzv+yM_%0tRm# zK@=&`05KO95y-&>iU=53(&&L=F7eTV&*h+Chk>__dr)j3G7=EZ2So#Nkb$BB29`8( dG9m{H*l=PaCBU1N4P+1t5Y_;VDF`hUFdG-N3j!RBdQ0mScmYyHY5+Q z0}U6)G%PbOCAC5?HwEm689+b4LI%wb!C^>FpC)oXf)i*S$jkt5MkWzv+yM_%0tRm# zK@=&`05KO95y-&>iU=53(&&L=F7eTV&*h+Chk>__dr)j3G7=EZ2So#Nkb$BB29`8( dG9m{H*l=PaCBU1N4P+1t5Y_;VDF Date: Thu, 26 Aug 2021 11:33:04 +0200 Subject: [PATCH 4/4] add test for stripping extra root dir MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- .../reading/tree/ZipArchiveResponse.test.ts | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/packages/backend-common/src/reading/tree/ZipArchiveResponse.test.ts b/packages/backend-common/src/reading/tree/ZipArchiveResponse.test.ts index 659875286e..f6f9a7845a 100644 --- a/packages/backend-common/src/reading/tree/ZipArchiveResponse.test.ts +++ b/packages/backend-common/src/reading/tree/ZipArchiveResponse.test.ts @@ -22,11 +22,15 @@ import { ZipArchiveResponse } from './ZipArchiveResponse'; const archiveData = fs.readFileSync( resolvePath(__filename, '../../__fixtures__/mock-main.zip'), ); +const archiveDataWithExtraDir = fs.readFileSync( + resolvePath(__filename, '../../__fixtures__/mock-with-extra-root-dir.zip'), +); describe('ZipArchiveResponse', () => { beforeEach(() => { mockFs({ '/test-archive.zip': archiveData, + '/test-archive-with-extra-root-dir.zip': archiveDataWithExtraDir, '/tmp': mockFs.directory(), }); }); @@ -58,6 +62,36 @@ describe('ZipArchiveResponse', () => { ]); }); + it('should read files and strip root dir if requested', async () => { + const stream = fs.createReadStream('/test-archive-with-extra-root-dir.zip'); + + const res = new ZipArchiveResponse( + stream, + '', + '/tmp', + 'etag', + undefined, + true, + ); + const files = await res.files(); + + expect(files).toEqual([ + { + path: 'mkdocs.yml', + content: expect.any(Function), + }, + { + path: 'docs/index.md', + content: expect.any(Function), + }, + ]); + const contents = await Promise.all(files.map(f => f.content())); + expect(contents.map(c => c.toString('utf8').trim())).toEqual([ + 'site_name: Test', + '# Test', + ]); + }); + it('should read files with filter', async () => { const stream = fs.createReadStream('/test-archive.zip');