From ec9e0b2b08728c878684ba0a8faca4b2e4c0f5a4 Mon Sep 17 00:00:00 2001 From: Miki Date: Fri, 21 Oct 2022 09:27:51 -0700 Subject: [PATCH] [Windows] Facilitate building of OSD and plugins (#2601) * [Windows] Replaces `rm -rf` with `remove.js` * [dev/build] Facilitates using zipped archives of node releases * [div/build] Introduces Windows as a platform * [dev/build] Corrects cleaning of platform specific build artifacts * [dev/build] Enhances the cleanup of downloaded node binaries * [opensearch-dashboards-plugin] Removes prohibition on installing plugins on Windows * [@osd/utils] Adds a method to standardize path references across platforms * [dev/build] Standardize paths in tests * [@osd/telemetry-tools] Normalizes the collection paths * [plugins/url-forwarding] Fixes the usage of `normalizePath` across node and browser * [@osd/pm] Allows symlink created for tests without elevated privileges on Windows * [@osd/opensearch] Allows usage of Windows snapshots in integration tests * [@osd/opensearch] Employs absolute paths in tests * [@osd/apm-config-loader] Employs absolute paths in tests * [core/server] Employs absolute and posix references to paths * [@osd/optimizer] Standardize paths in tests * [@osd/tests] Employs absolute paths in tests * [@osd/pm] Standardize paths in project trees * [plugins/telemetry] Accommodates the inability of Windows to create unreadable files for testing * [@osd/config-schema] Normalize paths in tests * [@osd/plugin-helpers] Standardize paths in tests * [@osd/plugin-generator] Standardize paths in tests * [Windows] Update changelog Signed-off-by: Miki --- CHANGELOG.md | 1 + package.json | 5 ++- .../src/utils/get_config_file_paths.test.ts | 2 +- .../__snapshots__/schema_error.test.ts.snap | 2 +- .../src/errors/schema_error.test.ts | 10 +++-- packages/osd-opensearch-archiver/package.json | 6 +-- packages/osd-opensearch/src/artifact.js | 8 ++-- packages/osd-opensearch/src/artifact.test.js | 4 +- .../src/utils/decompress.test.js | 4 +- .../src/utils/extract_config_files.test.js | 3 +- .../utils/find_most_recently_changed.test.js | 3 +- .../osd-optimizer/src/common/bundle.test.ts | 6 ++- .../src/optimizer/get_changes.test.ts | 15 +++++-- .../src/optimizer/get_plugin_bundles.test.ts | 5 +++ .../integration_tests/generate_plugin.test.ts | 12 ++++-- packages/osd-plugin-helpers/package.json | 2 +- .../src/integration_tests/build.test.ts | 12 ++++-- packages/osd-pm/src/utils/projects.test.ts | 3 +- packages/osd-pm/src/utils/projects_tree.ts | 3 +- .../src/tools/ts_parser.ts | 4 +- .../osd-telemetry-tools/src/tools/utils.ts | 5 ++- .../lib/suite_tracker.test.ts | 2 +- packages/osd-utils/src/path/index.ts | 26 ++++++++++++- scripts/remove.js | 31 +++++++++++++++ src/cli_plugin/install/pack.test.js | 5 ++- src/cli_plugin/install/settings.js | 4 +- src/cli_plugin/install/settings.test.js | 22 +++++++++-- src/cli_plugin/install/zip.test.js | 4 +- .../server/metrics/collectors/cgroup.test.ts | 7 +++- .../discovery/plugins_discovery.test.ts | 5 ++- .../integration_tests/plugins_service.test.ts | 4 +- src/core/server/plugins/plugin.test.ts | 3 +- src/core/server/plugins/plugin.ts | 4 +- .../server/plugins/plugins_service.test.ts | 3 +- src/dev/build/args.test.ts | 38 ++++++++++++++++++ src/dev/build/args.ts | 2 + src/dev/build/cli.ts | 7 ++-- src/dev/build/lib/config.test.ts | 15 ++++++- src/dev/build/lib/config.ts | 4 +- src/dev/build/lib/exec.test.ts | 6 ++- src/dev/build/lib/fs.ts | 39 ++++++++++++++++++- src/dev/build/lib/platform.ts | 1 + src/dev/build/tasks/clean_tasks.ts | 6 +-- .../tasks/nodejs/clean_node_builds_task.ts | 10 +++-- .../nodejs/extract_node_builds_task.test.ts | 19 ++++----- .../tasks/nodejs/extract_node_builds_task.ts | 9 +---- .../build/tasks/nodejs/node_download_info.ts | 2 +- .../usage/telemetry_usage_collector.test.ts | 11 +++++- .../public/forward_app/normalize_path.ts | 6 ++- .../plugins/osd_tp_run_pipeline/package.json | 2 +- .../plugins/app_link_test/package.json | 2 +- .../plugins/core_app_status/package.json | 2 +- .../plugins/core_plugin_a/package.json | 2 +- .../plugins/core_plugin_appleave/package.json | 2 +- .../plugins/core_plugin_b/package.json | 2 +- .../core_plugin_chromeless/package.json | 2 +- .../core_plugin_route_timeouts/package.json | 2 +- .../core_plugin_static_assets/package.json | 2 +- .../plugins/core_provider_plugin/package.json | 2 +- .../plugins/data_search/package.json | 2 +- .../doc_views_links_plugin/package.json | 4 +- .../plugins/doc_views_plugin/package.json | 2 +- .../plugins/index_patterns/package.json | 2 +- .../management_test_plugin/package.json | 2 +- .../opensearch_client_plugin/package.json | 2 +- .../osd_sample_panel_action/package.json | 2 +- .../plugins/osd_top_nav/package.json | 2 +- .../osd_tp_custom_visualizations/package.json | 2 +- .../plugins/rendering_plugin/package.json | 2 +- .../plugins/ui_settings_plugin/package.json | 2 +- yarn.lock | 7 +++- 71 files changed, 341 insertions(+), 120 deletions(-) create mode 100644 scripts/remove.js diff --git a/CHANGELOG.md b/CHANGELOG.md index c7e8507a964b..6a3ba9be5729 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) * [Multi DataSource] Make text content dynamically translated & update unit tests ([#2570](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2570)) * [Vis Builder] Change classname prefix wiz to vb ([#2581](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2581/files)) * [Vis Builder] Change wizard to vis_builder in file names and paths ([#2587](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2587)) +* [Windows] Facilitate building and running OSD and plugins on Windows platforms ([#2601](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2601)) * [Multi DataSource] Address UX comments on Data source list and create page ([#2625](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2625)) * [Vis Builder] Rename wizard to visBuilder in i18n id and formatted message id ([#2635](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2635)) diff --git a/package.json b/package.json index e87881fdb400..e491c823a5eb 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "makelogs": "node scripts/makelogs", "uiFramework:compileCss": "cd packages/osd-ui-framework && yarn compileCss", "osd:watch": "node scripts/opensearch_dashboards --dev --logging.json=false", - "build:types": "rm -rf ./target/types && tsc --p tsconfig.types.json", + "build:types": "node scripts/remove.js ./target/types && tsc --p tsconfig.types.json", "docs:acceptApiChanges": "node --max-old-space-size=6144 scripts/check_published_api_changes.js --accept", "osd:bootstrap": "node scripts/build_ts_refs && node scripts/register_git_hook", "spec_to_console": "node scripts/spec_to_console", @@ -412,6 +412,7 @@ "mutation-observer": "^1.0.3", "ngreact": "^0.5.1", "nock": "12.0.3", + "node-stream-zip": "^1.15.0", "normalize-path": "^3.0.0", "nyc": "^15.1.0", "pixelmatch": "^5.1.0", @@ -461,4 +462,4 @@ "node": "14.20.0", "yarn": "^1.21.1" } -} \ No newline at end of file +} diff --git a/packages/osd-apm-config-loader/src/utils/get_config_file_paths.test.ts b/packages/osd-apm-config-loader/src/utils/get_config_file_paths.test.ts index e730a4ef9fdd..32bff7f29394 100644 --- a/packages/osd-apm-config-loader/src/utils/get_config_file_paths.test.ts +++ b/packages/osd-apm-config-loader/src/utils/get_config_file_paths.test.ts @@ -40,7 +40,7 @@ describe('getConfigurationFilePaths', () => { expect(getConfigurationFilePaths(argv)).toEqual([ resolve(cwd, join('.', 'relative-path')), - '/absolute-path', + resolve('/absolute-path'), ]); }); diff --git a/packages/osd-config-schema/src/errors/__snapshots__/schema_error.test.ts.snap b/packages/osd-config-schema/src/errors/__snapshots__/schema_error.test.ts.snap index c34dd719e650..38f81a0cc62b 100644 --- a/packages/osd-config-schema/src/errors/__snapshots__/schema_error.test.ts.snap +++ b/packages/osd-config-schema/src/errors/__snapshots__/schema_error.test.ts.snap @@ -3,6 +3,6 @@ exports[`includes stack 1`] = ` "Error: test at new SchemaError (packages/osd-config-schema/src/errors/schema_error.ts:35:5) - at Object. (packages/osd-config-schema/src/errors/schema_error.test.ts:55:11) + at Object. (packages/osd-config-schema/src/errors/schema_error.test.ts:59:11) at new Promise ()" `; diff --git a/packages/osd-config-schema/src/errors/schema_error.test.ts b/packages/osd-config-schema/src/errors/schema_error.test.ts index c6ebd5d0dbd9..9e7b5a897081 100644 --- a/packages/osd-config-schema/src/errors/schema_error.test.ts +++ b/packages/osd-config-schema/src/errors/schema_error.test.ts @@ -28,7 +28,7 @@ * under the License. */ -import { relative } from 'path'; +import { relative, sep } from 'path'; import { SchemaError } from '.'; /** @@ -37,7 +37,7 @@ import { SchemaError } from '.'; export const cleanStack = (stack: string) => stack .split('\n') - .filter((line) => !line.includes('node_modules/') && !line.includes('internal/')) + .filter((line) => !line.includes('node_modules' + sep) && !line.includes('internal/')) .map((line) => { const parts = /.*\((.*)\).?/.exec(line) || []; @@ -46,7 +46,11 @@ export const cleanStack = (stack: string) => } const path = parts[1]; - return line.replace(path, relative(process.cwd(), path)); + // Cannot use `standardize` from `@osd/utils + let relativePath = relative(process.cwd(), path); + if (process.platform === 'win32') relativePath = relativePath.replace(/\\/g, '/'); + + return line.replace(path, relativePath); }) .join('\n'); diff --git a/packages/osd-opensearch-archiver/package.json b/packages/osd-opensearch-archiver/package.json index e1c28cc47484..f130ae44138a 100644 --- a/packages/osd-opensearch-archiver/package.json +++ b/packages/osd-opensearch-archiver/package.json @@ -7,8 +7,8 @@ "devOnly": true }, "scripts": { - "osd:bootstrap": "rm -rf target && tsc", - "osd:watch": "rm -rf target && tsc --watch" + "osd:bootstrap": "node ../../scripts/remove.js target && tsc", + "osd:watch": "node ../../scripts/remove.js target && tsc --watch" }, "dependencies": { "@osd/dev-utils": "1.0.0", @@ -17,4 +17,4 @@ "devDependencies": { "@types/elasticsearch": "^5.0.33" } -} \ No newline at end of file +} diff --git a/packages/osd-opensearch/src/artifact.js b/packages/osd-opensearch/src/artifact.js index 69f443245d4d..b7d8857ba09f 100644 --- a/packages/osd-opensearch/src/artifact.js +++ b/packages/osd-opensearch/src/artifact.js @@ -186,12 +186,14 @@ async function getArtifactSpecForSnapshotFromUrl(urlVersion, log) { // issue: https://github.com/opensearch-project/OpenSearch-Dashboards/issues/475 const platform = process.platform === 'win32' ? 'windows' : process.platform; const arch = process.arch === 'arm64' ? 'arm64' : 'x64'; - if (platform !== 'linux') { - throw createCliError(`Snapshots are only available for Linux`); + const extension = process.platform === 'win32' ? 'zip' : 'tar.gz'; + + if (platform !== 'linux' && platform !== 'windows') { + throw createCliError(`Snapshots are only available for Linux and Windows`); } const latestUrl = `${DAILY_SNAPSHOTS_BASE_URL}/${desiredVersion}-SNAPSHOT`; - const latestFile = `opensearch-min-${desiredVersion}-SNAPSHOT-${platform}-${arch}-latest.tar.gz`; + const latestFile = `opensearch-min-${desiredVersion}-SNAPSHOT-${platform}-${arch}-latest.${extension}`; const completeLatestUrl = `${latestUrl}/${latestFile}`; let { abc, resp } = await verifySnapshotUrl(completeLatestUrl, log); diff --git a/packages/osd-opensearch/src/artifact.test.js b/packages/osd-opensearch/src/artifact.test.js index b9c331517c74..1d5d0bdf330c 100644 --- a/packages/osd-opensearch/src/artifact.test.js +++ b/packages/osd-opensearch/src/artifact.test.js @@ -163,10 +163,10 @@ describe('Artifact', () => { }); }); - it('should throw when on a non-Linux platform', async () => { + it('should throw when on a non-Linux or non-Windows platform', async () => { Object.defineProperties(process, { platform: { - value: 'win32', + value: 'darwin', }, arch: { value: ORIGINAL_ARCHITECTURE, diff --git a/packages/osd-opensearch/src/utils/decompress.test.js b/packages/osd-opensearch/src/utils/decompress.test.js index e9e163c3ebc2..bf30b49eebaa 100644 --- a/packages/osd-opensearch/src/utils/decompress.test.js +++ b/packages/osd-opensearch/src/utils/decompress.test.js @@ -52,8 +52,8 @@ beforeEach(() => { fs.copyFileSync(path.resolve(fixturesFolder, 'snapshot.tar.gz'), tarGzSnapshot); }); -afterEach(() => { - del.sync(tmpFolder, { force: true }); +afterEach(async () => { + await del(tmpFolder, { force: true }); }); test('zip strips root directory', async () => { diff --git a/packages/osd-opensearch/src/utils/extract_config_files.test.js b/packages/osd-opensearch/src/utils/extract_config_files.test.js index 3d73d821dbc5..c9da144f6e3c 100644 --- a/packages/osd-opensearch/src/utils/extract_config_files.test.js +++ b/packages/osd-opensearch/src/utils/extract_config_files.test.js @@ -36,6 +36,7 @@ jest.mock('fs', () => ({ const { extractConfigFiles } = require('./extract_config_files'); const fs = require('fs'); +const path = require('path'); afterEach(() => { jest.clearAllMocks(); @@ -55,7 +56,7 @@ test('copies file', () => { extractConfigFiles(['path=/data/foo.yml'], '/opensearch'); expect(fs.readFileSync.mock.calls[0][0]).toEqual('/data/foo.yml'); - expect(fs.writeFileSync.mock.calls[0][0]).toEqual('/opensearch/config/foo.yml'); + expect(fs.writeFileSync.mock.calls[0][0]).toEqual(path.resolve('/opensearch/config/foo.yml')); }); test('ignores file which does not exist', () => { diff --git a/packages/osd-opensearch/src/utils/find_most_recently_changed.test.js b/packages/osd-opensearch/src/utils/find_most_recently_changed.test.js index 235ce9fd6690..10b3dd78ff94 100644 --- a/packages/osd-opensearch/src/utils/find_most_recently_changed.test.js +++ b/packages/osd-opensearch/src/utils/find_most_recently_changed.test.js @@ -27,6 +27,7 @@ * specific language governing permissions and limitations * under the License. */ +const path = require('path'); jest.mock('fs', () => ({ statSync: jest.fn().mockImplementation((path) => { @@ -57,7 +58,7 @@ const { findMostRecentlyChanged } = require('./find_most_recently_changed'); test('returns newest file', () => { const file = findMostRecentlyChanged('/data/*.yml'); - expect(file).toEqual('/data/newest.yml'); + expect(file).toEqual(path.resolve('/data/newest.yml')); }); afterAll(() => { diff --git a/packages/osd-optimizer/src/common/bundle.test.ts b/packages/osd-optimizer/src/common/bundle.test.ts index 16aa012cf91d..ceb7eff4b1db 100644 --- a/packages/osd-optimizer/src/common/bundle.test.ts +++ b/packages/osd-optimizer/src/common/bundle.test.ts @@ -28,6 +28,7 @@ * under the License. */ +import { resolve } from 'path'; import { Bundle, BundleSpec, parseBundles } from './bundle'; jest.mock('fs'); @@ -88,13 +89,16 @@ it('provides the module count from the cache', () => { it('parses bundles from JSON specs', () => { const bundles = parseBundles(JSON.stringify([SPEC])); + let expectedCachePath = resolve('/foo/bar/target/.osd-optimizer-cache'); + // Cannot use `standardize` from `@osd/util` due to mocking of fs + if (process?.platform === 'win32') expectedCachePath = expectedCachePath.replace(/\\/g, '\\\\'); expect(bundles).toMatchInlineSnapshot(` Array [ Bundle { "banner": undefined, "cache": BundleCache { - "path": "/foo/bar/target/.osd-optimizer-cache", + "path": "${expectedCachePath}", "state": undefined, }, "contextDir": "/foo/bar", diff --git a/packages/osd-optimizer/src/optimizer/get_changes.test.ts b/packages/osd-optimizer/src/optimizer/get_changes.test.ts index 071bb8e1a260..44e1637d5437 100644 --- a/packages/osd-optimizer/src/optimizer/get_changes.test.ts +++ b/packages/osd-optimizer/src/optimizer/get_changes.test.ts @@ -28,9 +28,12 @@ * under the License. */ +import path from 'path'; + jest.mock('execa'); import { getChanges } from './get_changes'; +import { standardize } from '@osd/dev-utils'; const execa: jest.Mock = jest.requireMock('execa'); @@ -56,12 +59,16 @@ it('parses git ls-files output', async () => { }; }); + const rootPath = path.resolve('/foo/bar/x/osd-optimizer') + path.sep; + const srcPath = path.join(rootPath, 'src') + path.sep; + const commonPath = path.join(srcPath, 'common') + path.sep; + await expect(getChanges('/foo/bar/x')).resolves.toMatchInlineSnapshot(` Map { - "/foo/bar/x/osd-optimizer/package.json" => "modified", - "/foo/bar/x/osd-optimizer/src/common/bundle.ts" => "modified", - "/foo/bar/x/osd-optimizer/src/common/bundles.ts" => "deleted", - "/foo/bar/x/osd-optimizer/src/get_bundle_definitions.test.ts" => "deleted", + "${standardize(rootPath, false, true)}package.json" => "modified", + "${standardize(commonPath, false, true)}bundle.ts" => "modified", + "${standardize(commonPath, false, true)}bundles.ts" => "deleted", + "${standardize(srcPath, false, true)}get_bundle_definitions.test.ts" => "deleted", } `); }); diff --git a/packages/osd-optimizer/src/optimizer/get_plugin_bundles.test.ts b/packages/osd-optimizer/src/optimizer/get_plugin_bundles.test.ts index 608b16a3661d..28ee6179f011 100644 --- a/packages/osd-optimizer/src/optimizer/get_plugin_bundles.test.ts +++ b/packages/osd-optimizer/src/optimizer/get_plugin_bundles.test.ts @@ -31,10 +31,15 @@ import { createAbsolutePathSerializer } from '@osd/dev-utils'; import { getPluginBundles } from './get_plugin_bundles'; +import path from 'path'; expect.addSnapshotSerializer(createAbsolutePathSerializer('/repo', '')); expect.addSnapshotSerializer(createAbsolutePathSerializer('/output', '')); +expect.addSnapshotSerializer(createAbsolutePathSerializer(path.resolve('/output'), '')); expect.addSnapshotSerializer(createAbsolutePathSerializer('/outside/of/repo', '')); +expect.addSnapshotSerializer( + createAbsolutePathSerializer(path.resolve('/outside/of/repo'), '') +); it('returns a bundle for core and each plugin', () => { expect( diff --git a/packages/osd-plugin-generator/src/integration_tests/generate_plugin.test.ts b/packages/osd-plugin-generator/src/integration_tests/generate_plugin.test.ts index 51378b14470d..45ec5a6986a1 100644 --- a/packages/osd-plugin-generator/src/integration_tests/generate_plugin.test.ts +++ b/packages/osd-plugin-generator/src/integration_tests/generate_plugin.test.ts @@ -32,13 +32,17 @@ import Path from 'path'; import del from 'del'; import execa from 'execa'; -import { REPO_ROOT } from '@osd/utils'; -import { createAbsolutePathSerializer } from '@osd/dev-utils'; +import { REPO_ROOT, standardize, createAbsolutePathSerializer } from '@osd/dev-utils'; import globby from 'globby'; -const GENERATED_DIR = Path.resolve(REPO_ROOT, `plugins`); +// Has to be a posix reference because it is used to generate glob patterns +const GENERATED_DIR = standardize(Path.resolve(REPO_ROOT, `plugins`), true); -expect.addSnapshotSerializer(createAbsolutePathSerializer()); +expect.addSnapshotSerializer( + createAbsolutePathSerializer( + process?.platform === 'win32' ? standardize(REPO_ROOT, true) : REPO_ROOT + ) +); beforeEach(async () => { await del([`${GENERATED_DIR}/**`, `!${GENERATED_DIR}`, `!${GENERATED_DIR}/.gitignore`], { diff --git a/packages/osd-plugin-helpers/package.json b/packages/osd-plugin-helpers/package.json index 447199730184..3738aae36b1a 100644 --- a/packages/osd-plugin-helpers/package.json +++ b/packages/osd-plugin-helpers/package.json @@ -12,7 +12,7 @@ "plugin-helpers": "bin/plugin-helpers.js" }, "scripts": { - "osd:bootstrap": "rm -rf target && tsc", + "osd:bootstrap": "node ../../scripts/remove.js && tsc", "osd:watch": "tsc --watch" }, "dependencies": { diff --git a/packages/osd-plugin-helpers/src/integration_tests/build.test.ts b/packages/osd-plugin-helpers/src/integration_tests/build.test.ts index 4dc550e5004e..35195f9bc163 100644 --- a/packages/osd-plugin-helpers/src/integration_tests/build.test.ts +++ b/packages/osd-plugin-helpers/src/integration_tests/build.test.ts @@ -32,8 +32,12 @@ import Path from 'path'; import Fs from 'fs'; import execa from 'execa'; -import { REPO_ROOT } from '@osd/utils'; -import { createStripAnsiSerializer, createReplaceSerializer } from '@osd/dev-utils'; +import { + REPO_ROOT, + standardize, + createStripAnsiSerializer, + createReplaceSerializer, +} from '@osd/dev-utils'; import extract from 'extract-zip'; import del from 'del'; import globby from 'globby'; @@ -78,7 +82,7 @@ it('builds a generated plugin into a viable archive', async () => { expect(generateProc.all).toMatchInlineSnapshot(` " succ 🎉 - Your plugin has been created in plugins/foo_test_plugin + Your plugin has been created in ${standardize('plugins/foo_test_plugin', false, true)} " `); @@ -165,7 +169,7 @@ it('builds a non-semver generated plugin into a viable archive', async () => { expect(generateProc.all).toMatchInlineSnapshot(` " succ 🎉 - Your plugin has been created in plugins/foo_test_plugin + Your plugin has been created in ${standardize('plugins/foo_test_plugin', false, true)} " `); diff --git a/packages/osd-pm/src/utils/projects.test.ts b/packages/osd-pm/src/utils/projects.test.ts index 57935452feb9..545b435a7e09 100644 --- a/packages/osd-pm/src/utils/projects.test.ts +++ b/packages/osd-pm/src/utils/projects.test.ts @@ -53,7 +53,8 @@ describe('#getProjects', () => { await promisify(symlink)( join(__dirname, '__fixtures__/symlinked-plugins/corge'), - join(rootPlugins, 'corge') + join(rootPlugins, 'corge'), + 'junction' // This parameter would only be used on Windows ); }); diff --git a/packages/osd-pm/src/utils/projects_tree.ts b/packages/osd-pm/src/utils/projects_tree.ts index 5a455f35ea63..41f9e4331098 100644 --- a/packages/osd-pm/src/utils/projects_tree.ts +++ b/packages/osd-pm/src/utils/projects_tree.ts @@ -31,6 +31,7 @@ import chalk from 'chalk'; import path from 'path'; +import { standardize } from '@osd/utils'; import { Project } from './project'; const projectKey = Symbol('__project'); @@ -117,7 +118,7 @@ function createTreeStructure(tree: IProjectsTree): ITree { // `foo/bar/baz` instead. if (subtree.children && subtree.children.length === 1) { const child = subtree.children[0]; - const newName = chalk.dim(path.join(dir.toString(), child.name!)); + const newName = chalk.dim(standardize(path.join(dir.toString(), child.name!), true)); children.push({ children: child.children, diff --git a/packages/osd-telemetry-tools/src/tools/ts_parser.ts b/packages/osd-telemetry-tools/src/tools/ts_parser.ts index 2932bd76d470..31940dcfdfd3 100644 --- a/packages/osd-telemetry-tools/src/tools/ts_parser.ts +++ b/packages/osd-telemetry-tools/src/tools/ts_parser.ts @@ -31,7 +31,7 @@ import * as ts from 'typescript'; import { createFailError } from '@osd/dev-utils'; import * as path from 'path'; -import { getProperty, getPropertyValue } from './utils'; +import { getProperty, getPropertyValue, normalizePath } from './utils'; import { getDescriptor, Descriptor } from './serializer'; export function* traverseNodes(maybeNodes: ts.Node | ts.Node[]): Generator { @@ -205,7 +205,7 @@ export function* parseUsageCollection( sourceFile: ts.SourceFile, program: ts.Program ): Generator { - const relativePath = path.relative(process.cwd(), sourceFile.fileName); + const relativePath = normalizePath(path.relative(process.cwd(), sourceFile.fileName), false); if (sourceHasUsageCollector(sourceFile)) { for (const node of traverseNodes(sourceFile)) { if (isMakeUsageCollectorFunction(node, sourceFile)) { diff --git a/packages/osd-telemetry-tools/src/tools/utils.ts b/packages/osd-telemetry-tools/src/tools/utils.ts index 3df213f82784..237175769479 100644 --- a/packages/osd-telemetry-tools/src/tools/utils.ts +++ b/packages/osd-telemetry-tools/src/tools/utils.ts @@ -311,6 +311,7 @@ export function difference(actual: any, expected: any) { return changes(actual, expected); } -export function normalizePath(inputPath: string) { - return normalize(path.relative('.', inputPath)); +export function normalizePath(inputPath: string, relativeToRoot: boolean = true) { + if (relativeToRoot) return normalize(path.relative('.', inputPath)); + return normalize(inputPath); } diff --git a/packages/osd-test/src/functional_test_runner/lib/suite_tracker.test.ts b/packages/osd-test/src/functional_test_runner/lib/suite_tracker.test.ts index f7c45727734c..cc628b9de811 100644 --- a/packages/osd-test/src/functional_test_runner/lib/suite_tracker.test.ts +++ b/packages/osd-test/src/functional_test_runner/lib/suite_tracker.test.ts @@ -40,7 +40,7 @@ import { REPO_ROOT } from '@osd/dev-utils'; import { Lifecycle } from './lifecycle'; import { SuiteTracker } from './suite_tracker'; -const DEFAULT_TEST_METADATA_PATH = join(REPO_ROOT, 'target', 'test_metadata.json'); +const DEFAULT_TEST_METADATA_PATH = resolve(REPO_ROOT, 'target', 'test_metadata.json'); const MOCK_CONFIG_PATH = join('test', 'config.js'); const MOCK_TEST_PATH = join('test', 'apps', 'test.js'); const ENVS_TO_RESET = ['TEST_METADATA_PATH']; diff --git a/packages/osd-utils/src/path/index.ts b/packages/osd-utils/src/path/index.ts index c661b04fb6ad..263d2d39ac36 100644 --- a/packages/osd-utils/src/path/index.ts +++ b/packages/osd-utils/src/path/index.ts @@ -28,7 +28,7 @@ * under the License. */ -import { join } from 'path'; +import { join, normalize } from 'path'; import { accessSync, constants } from 'fs'; import { TypeOf, schema } from '@osd/config-schema'; import { REPO_ROOT } from '../repo_root'; @@ -94,3 +94,27 @@ export const config = { data: schema.string({ defaultValue: () => getDataPath() }), }), }; + +/** + * Get a standardized reference to a path + * @param {string} path - the path to standardize + * @param {boolean} [usePosix=true] - produce a posix reference + * @param {boolean} [escapedBackslashes=true] - on Windows, double-backslash the reference + * @internal + */ +export const standardize = ( + path: string, + usePosix: boolean = true, + escapedBackslashes: boolean = true +) => { + /* Force os-dependant separators + * path.posix.normalize doesn't convert backslashes to slashes on Windows so we manually force it afterwards + */ + const normal = normalize(path); + + // Filter out in-browser executions as well as non-windows ones + if (process?.platform !== 'win32') return normal; + + if (usePosix) return normal.replace(/\\/g, '/'); + return escapedBackslashes ? normal.replace(/\\/g, '\\\\') : normal; +}; diff --git a/scripts/remove.js b/scripts/remove.js new file mode 100644 index 000000000000..cc3c62739371 --- /dev/null +++ b/scripts/remove.js @@ -0,0 +1,31 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/* eslint no-restricted-syntax: 0 */ +const del = require('del'); +const path = require('path'); + +if (!process.argv.includes(__filename)) { + console.error('Usage: node scripts/remove.js '); + process.exit(1); +} + +const toDeletes = process.argv + .slice(process.argv.indexOf(__filename + 1)) + .map((item) => path.resolve(item)); + +if (toDeletes.length === 0) { + console.warn('Nothing to delete'); + process.exit(0); +} + +(async () => { + const deletedPaths = await del(toDeletes); + if (deletedPaths === 0) { + console.warn('Nothing deleted'); + } else { + console.log('Deleted files and directories:\n\t', deletedPaths.join('\n\t')); + } +})(); diff --git a/src/cli_plugin/install/pack.test.js b/src/cli_plugin/install/pack.test.js index 5520e34bc3bb..783593c6d9fa 100644 --- a/src/cli_plugin/install/pack.test.js +++ b/src/cli_plugin/install/pack.test.js @@ -72,10 +72,11 @@ describe('opensearchDashboards cli', function () { Fs.mkdirSync(testWorkingPath, { recursive: true }); }); - afterEach(function () { + afterEach(async () => { logger.log.restore(); logger.error.restore(); - del.sync(workingPathRoot); + + await del(workingPathRoot); }); function copyReplyFile(filename) { diff --git a/src/cli_plugin/install/settings.js b/src/cli_plugin/install/settings.js index 3d7cdec3d620..2b0c34bfcd37 100644 --- a/src/cli_plugin/install/settings.js +++ b/src/cli_plugin/install/settings.js @@ -44,9 +44,7 @@ function generateUrls({ version, plugin }) { function generatePluginUrl(version, plugin) { const platform = process.platform === 'win32' ? 'windows' : process.platform; const arch = process.arch === 'arm64' ? 'arm64' : 'x64'; - if (platform !== 'linux') { - throw new Error('Plugins are only available for Linux'); - } + return `${LATEST_PLUGIN_BASE_URL}/${version}/latest/${platform}/${arch}/tar/builds/opensearch-dashboards/plugins/${plugin}-${version}.zip`; } diff --git a/src/cli_plugin/install/settings.test.js b/src/cli_plugin/install/settings.test.js index dc769496e9e4..ac7cf94e6761 100644 --- a/src/cli_plugin/install/settings.test.js +++ b/src/cli_plugin/install/settings.test.js @@ -137,7 +137,7 @@ describe('parse function', function () { `); }); - it('should throw when on a non-Linux platform', function () { + it('produces expected results on Windows', function () { Object.defineProperties(process, { platform: { value: 'win32', @@ -146,9 +146,23 @@ describe('parse function', function () { value: 'x64', }, }); - expect(() => parse(command, { ...defaultOptions }, osdPackage)).toThrow( - 'Plugins are only available for Linux' - ); + expect(parse(command, { ...defaultOptions }, osdPackage)).toMatchInlineSnapshot(` + Object { + "config": "", + "plugin": "plugin name", + "pluginDir": /plugins, + "quiet": false, + "silent": false, + "tempArchiveFile": /plugins/.plugin.installing/archive.part, + "timeout": 0, + "urls": Array [ + "plugin name", + "https://ci.opensearch.org/ci/dbc/distribution-build-opensearch-dashboards/1234/latest/windows/x64/tar/builds/opensearch-dashboards/plugins/plugin name-1234.zip", + ], + "version": 1234, + "workingPath": /plugins/.plugin.installing, + } + `); }); it('should not throw when on a non-x64 arch', function () { diff --git a/src/cli_plugin/install/zip.test.js b/src/cli_plugin/install/zip.test.js index f010acdd8295..206b091c367d 100644 --- a/src/cli_plugin/install/zip.test.js +++ b/src/cli_plugin/install/zip.test.js @@ -48,8 +48,8 @@ describe('opensearchDashboards cli', function () { tempPath = path.resolve(os.tmpdir(), randomDir); }); - afterEach(() => { - del.sync(tempPath, { force: true }); + afterEach(async () => { + await del(tempPath, { force: true }); }); describe('analyzeArchive', function () { diff --git a/src/core/server/metrics/collectors/cgroup.test.ts b/src/core/server/metrics/collectors/cgroup.test.ts index 633b3c8aeae5..50fc952566bc 100644 --- a/src/core/server/metrics/collectors/cgroup.test.ts +++ b/src/core/server/metrics/collectors/cgroup.test.ts @@ -31,6 +31,7 @@ import mockFs from 'mock-fs'; import { loggerMock } from '@osd/logging/target/mocks'; import { OsCgroupMetricsCollector } from './cgroup'; +import path from 'path'; describe('OsCgroupMetricsCollector', () => { afterEach(() => mockFs.restore()); @@ -140,10 +141,14 @@ throttled_time 666 const logger = loggerMock.create(); + const usagePath = + (process.platform === 'win32' ? '\\\\?\\' : '') + + path.resolve('/sys/fs/cgroup/cpuacct/groupname/cpuacct.usage'); + const collector = new OsCgroupMetricsCollector({ logger }); expect(await collector.collect()).toEqual({}); expect(logger.error).toHaveBeenCalledWith( - "cgroup metrics could not be read due to error: [Error: EACCES, permission denied '/sys/fs/cgroup/cpuacct/groupname/cpuacct.usage']" + `cgroup metrics could not be read due to error: [Error: EACCES, permission denied '${usagePath}']` ); }); }); diff --git a/src/core/server/plugins/discovery/plugins_discovery.test.ts b/src/core/server/plugins/discovery/plugins_discovery.test.ts index bc7480bb8adb..92b2cb71ef98 100644 --- a/src/core/server/plugins/discovery/plugins_discovery.test.ts +++ b/src/core/server/plugins/discovery/plugins_discovery.test.ts @@ -44,6 +44,7 @@ import { discover } from './plugins_discovery'; import { CoreContext } from '../../core_context'; const OPENSEARCH_DASHBOARDS_ROOT = process.cwd(); +const EXTENDED_PATH_PREFIX = process.platform === 'win32' ? '\\\\?\\' : ''; const Plugins = { invalid: () => ({ @@ -243,7 +244,7 @@ describe('plugins discovery system', () => { const srcPluginsPath = resolve(OPENSEARCH_DASHBOARDS_ROOT, 'src', 'plugins'); expect(errors).toEqual( expect.arrayContaining([ - `Error: EACCES, permission denied '${srcPluginsPath}' (invalid-search-path, ${srcPluginsPath})`, + `Error: EACCES, permission denied '${EXTENDED_PATH_PREFIX}${srcPluginsPath}' (invalid-search-path, ${srcPluginsPath})`, ]) ); }); @@ -278,7 +279,7 @@ describe('plugins discovery system', () => { const errorPath = manifestPath('plugin_a'); expect(errors).toEqual( expect.arrayContaining([ - `Error: EACCES, permission denied '${errorPath}' (missing-manifest, ${errorPath})`, + `Error: EACCES, permission denied '${EXTENDED_PATH_PREFIX}${errorPath}' (missing-manifest, ${errorPath})`, ]) ); }); diff --git a/src/core/server/plugins/integration_tests/plugins_service.test.ts b/src/core/server/plugins/integration_tests/plugins_service.test.ts index 29396d0acce6..34310ea3de37 100644 --- a/src/core/server/plugins/integration_tests/plugins_service.test.ts +++ b/src/core/server/plugins/integration_tests/plugins_service.test.ts @@ -32,7 +32,7 @@ import { REPO_ROOT } from '@osd/dev-utils'; import { mockPackage, mockDiscover } from './plugins_service.test.mocks'; -import { join } from 'path'; +import { posix } from 'path'; import { PluginsService } from '../plugins_service'; import { ConfigPath, ConfigService, Env } from '../../config'; @@ -163,7 +163,7 @@ describe('PluginsService', () => { } as Plugin); jest.doMock( - join(pluginPath, 'server'), + posix.join(pluginPath, 'server'), () => ({ plugin: pluginInitializer, }), diff --git a/src/core/server/plugins/plugin.test.ts b/src/core/server/plugins/plugin.test.ts index 1858f7557adb..9543d379493c 100644 --- a/src/core/server/plugins/plugin.test.ts +++ b/src/core/server/plugins/plugin.test.ts @@ -28,7 +28,7 @@ * under the License. */ -import { join } from 'path'; +import { posix } from 'path'; import { BehaviorSubject } from 'rxjs'; import { REPO_ROOT } from '@osd/dev-utils'; import { schema } from '@osd/config-schema'; @@ -47,6 +47,7 @@ import { InstanceInfo, } from './plugin_context'; +const { join } = posix; const mockPluginInitializer = jest.fn(); const logger = loggingSystemMock.create(); jest.doMock( diff --git a/src/core/server/plugins/plugin.ts b/src/core/server/plugins/plugin.ts index 7dbe4da4cc51..89a2aecc82f3 100644 --- a/src/core/server/plugins/plugin.ts +++ b/src/core/server/plugins/plugin.ts @@ -28,7 +28,7 @@ * under the License. */ -import { join } from 'path'; +import { posix } from 'path'; import typeDetect from 'type-detect'; import { Subject } from 'rxjs'; import { first } from 'rxjs/operators'; @@ -45,6 +45,8 @@ import { } from './types'; import { CoreSetup, CoreStart } from '..'; +const { join } = posix; + /** * Lightweight wrapper around discovered plugin that is responsible for instantiating * plugin and dispatching proper context and dependencies into plugin's lifecycle hooks. diff --git a/src/core/server/plugins/plugins_service.test.ts b/src/core/server/plugins/plugins_service.test.ts index cc4ac5e65fa5..cff5ae79b914 100644 --- a/src/core/server/plugins/plugins_service.test.ts +++ b/src/core/server/plugins/plugins_service.test.ts @@ -30,7 +30,7 @@ import { mockDiscover, mockPackage } from './plugins_service.test.mocks'; -import { resolve, join } from 'path'; +import { resolve, posix } from 'path'; import { BehaviorSubject, from } from 'rxjs'; import { schema } from '@osd/config-schema'; import { createAbsolutePathSerializer, REPO_ROOT } from '@osd/dev-utils'; @@ -48,6 +48,7 @@ import { config } from './plugins_config'; import { take } from 'rxjs/operators'; import { DiscoveredPlugin } from './types'; +const { join } = posix; const MockPluginsSystem: jest.Mock = PluginsSystem as any; let pluginsService: PluginsService; diff --git a/src/dev/build/args.test.ts b/src/dev/build/args.test.ts index 262305f62250..2304c560a687 100644 --- a/src/dev/build/args.test.ts +++ b/src/dev/build/args.test.ts @@ -62,6 +62,7 @@ it('build dist for current platform, without packages, by default', () => { "darwin": false, "linux": false, "linuxArm": false, + "windows": false, }, "versionQualifier": "", }, @@ -90,6 +91,7 @@ it('build dist for linux x64 platform, without packages, if --linux is passed', "darwin": false, "linux": true, "linuxArm": false, + "windows": false, }, "versionQualifier": "", }, @@ -118,6 +120,7 @@ it('build dist for linux arm64 platform, without packages, if --linux-arm is pas "darwin": false, "linux": false, "linuxArm": true, + "windows": false, }, "versionQualifier": "", }, @@ -146,6 +149,36 @@ it('build dist for darwin x64 platform, without packages, if --darwin is passed' "darwin": true, "linux": false, "linuxArm": false, + "windows": false, + }, + "versionQualifier": "", + }, + "log": , + "showHelp": false, + "unknownFlags": Array [], + } + `); +}); + +it('build dist for windows x64 platform, without packages, if --windows is passed', () => { + expect(readCliArgs(['node', 'scripts/build-platform', '--windows'])).toMatchInlineSnapshot(` + Object { + "buildOptions": Object { + "createArchives": true, + "createDebArmPackage": false, + "createDebPackage": false, + "createDockerPackage": false, + "createDockerUbiPackage": false, + "createRpmArmPackage": false, + "createRpmPackage": false, + "downloadFreshNode": true, + "isRelease": false, + "targetAllPlatforms": false, + "targetPlatforms": Object { + "darwin": false, + "linux": false, + "linuxArm": false, + "windows": true, }, "versionQualifier": "", }, @@ -174,6 +207,7 @@ it('builds packages if --all-platforms is passed', () => { "darwin": false, "linux": false, "linuxArm": false, + "windows": false, }, "versionQualifier": "", }, @@ -202,6 +236,7 @@ it('limits packages if --rpm passed with --all-platforms', () => { "darwin": false, "linux": false, "linuxArm": false, + "windows": false, }, "versionQualifier": "", }, @@ -230,6 +265,7 @@ it('limits packages if --deb passed with --all-platforms', () => { "darwin": false, "linux": false, "linuxArm": false, + "windows": false, }, "versionQualifier": "", }, @@ -259,6 +295,7 @@ it('limits packages if --docker passed with --all-platforms', () => { "darwin": false, "linux": false, "linuxArm": false, + "windows": false, }, "versionQualifier": "", }, @@ -288,6 +325,7 @@ it('limits packages if --docker passed with --skip-docker-ubi and --all-platform "darwin": false, "linux": false, "linuxArm": false, + "windows": false, }, "versionQualifier": "", }, diff --git a/src/dev/build/args.ts b/src/dev/build/args.ts index 7c16b6de5393..7e131174e330 100644 --- a/src/dev/build/args.ts +++ b/src/dev/build/args.ts @@ -50,6 +50,7 @@ export function readCliArgs(argv: string[]) { 'verbose', 'debug', 'all-platforms', + 'windows', 'darwin', 'linux', 'linux-arm', @@ -130,6 +131,7 @@ export function readCliArgs(argv: string[]) { createDockerPackage: isOsPackageDesired('docker'), createDockerUbiPackage: isOsPackageDesired('docker') && !Boolean(flags['skip-docker-ubi']), targetPlatforms: { + windows: Boolean(flags.windows), darwin: Boolean(flags.darwin), linux: Boolean(flags.linux), linuxArm: Boolean(flags['linux-arm']), diff --git a/src/dev/build/cli.ts b/src/dev/build/cli.ts index 0153a1768c9b..b075a6047acd 100644 --- a/src/dev/build/cli.ts +++ b/src/dev/build/cli.ts @@ -58,9 +58,10 @@ if (showHelp) { --skip-archives {dim Don't produce tar/zip archives} --skip-os-packages {dim Don't produce rpm/deb/docker packages} --all-platforms {dim Produce archives for all platforms, not just this one} - --linux {dim Produce archives for only linux x64 platform} - --linux-arm {dim Produce archives for only linux arm64 platform} - --darwin {dim Produce archives for only darwin x64 platform} + --linux {dim Produce archives only for linux x64 platform} + --linux-arm {dim Produce archives only for linux arm64 platform} + --darwin {dim Produce archives only for darwin x64 platform} + --windows {dim Produce archives only for windows x64 platform} --rpm {dim Only build the rpm package} --deb {dim Only build the deb package} --docker {dim Only build the docker image} diff --git a/src/dev/build/lib/config.test.ts b/src/dev/build/lib/config.test.ts index 57b9775bf3f2..db96a8c18dd0 100644 --- a/src/dev/build/lib/config.test.ts +++ b/src/dev/build/lib/config.test.ts @@ -30,7 +30,7 @@ import { resolve } from 'path'; -import { REPO_ROOT } from '@osd/utils'; +import { REPO_ROOT, standardize } from '@osd/utils'; import { createAbsolutePathSerializer } from '@osd/dev-utils'; import pkg from '../../../../package.json'; @@ -54,6 +54,7 @@ const setup = async ({ darwin: false, linux: false, linuxArm: false, + windows: false, }, }: { targetAllPlatforms?: boolean; @@ -61,6 +62,7 @@ const setup = async ({ darwin: boolean; linux: boolean; linuxArm: boolean; + windows: boolean; }; } = {}) => { return await Config.create({ @@ -87,7 +89,9 @@ describe('#getNodeVersion()', () => { describe('#getRepoRelativePath()', () => { it('converts an absolute path to relative path, from the root of the repo', async () => { const config = await setup(); - expect(config.getRepoRelativePath(__dirname)).toMatchInlineSnapshot(`"src/dev/build/lib"`); + expect(config.getRepoRelativePath(__dirname)).toMatchInlineSnapshot( + `"${standardize('src/dev/build/lib', false, true)}"` + ); }); }); @@ -115,6 +119,7 @@ describe('#hasSpecifiedPlatform', () => { darwin: true, linux: false, linuxArm: false, + windows: false, }, }); expect(config.hasSpecifiedPlatform() === true); @@ -127,6 +132,7 @@ describe('#hasSpecifiedPlatform', () => { darwin: false, linux: false, linuxArm: true, + windows: false, }, }); expect(config.hasSpecifiedPlatform() === true); @@ -139,6 +145,7 @@ describe('#hasSpecifiedPlatform', () => { darwin: false, linux: true, linuxArm: false, + windows: false, }, }); expect(config.hasSpecifiedPlatform() === true); @@ -205,6 +212,7 @@ describe('#getTargetPlatforms()', () => { darwin: true, linux: false, linuxArm: false, + windows: false, }, }); @@ -227,6 +235,7 @@ describe('#getTargetPlatforms()', () => { darwin: false, linux: true, linuxArm: false, + windows: false, }, }); @@ -249,6 +258,7 @@ describe('#getTargetPlatforms()', () => { darwin: false, linux: false, linuxArm: true, + windows: false, }, }); @@ -271,6 +281,7 @@ describe('#getTargetPlatforms()', () => { darwin: true, linux: false, linuxArm: true, + windows: false, }, }); diff --git a/src/dev/build/lib/config.ts b/src/dev/build/lib/config.ts index 2804a702be42..4f47a5ec8f50 100644 --- a/src/dev/build/lib/config.ts +++ b/src/dev/build/lib/config.ts @@ -143,6 +143,7 @@ export class Config { const platforms: Platform[] = []; if (this.targetPlatforms.darwin) platforms.push(this.getPlatform('darwin', 'x64')); if (this.targetPlatforms.linux) platforms.push(this.getPlatform('linux', 'x64')); + if (this.targetPlatforms.windows) platforms.push(this.getPlatform('win32', 'x64')); if (this.targetPlatforms.linuxArm) platforms.push(this.getPlatform('linux', 'arm64')); if (platforms.length > 0) return platforms; @@ -153,7 +154,7 @@ export class Config { /** * Return the list of Platforms we need/have node downloads for. We always * include the linux platform even if we aren't targeting linux so we can - * reliably get the LICENSE file, which isn't included in the windows version + * reliably get the LICENSE file. */ getNodePlatforms() { if (this.targetAllPlatforms) { @@ -164,6 +165,7 @@ export class Config { return [this.getPlatform('linux', 'x64')]; } + // ToDo: All node dists, including Windows, contain a LICENSE file; do we still need to do this? return [this.getPlatformForThisOs(), this.getPlatform('linux', 'x64')]; } diff --git a/src/dev/build/lib/exec.test.ts b/src/dev/build/lib/exec.test.ts index 2dc75b3a311c..7257f7f88db7 100644 --- a/src/dev/build/lib/exec.test.ts +++ b/src/dev/build/lib/exec.test.ts @@ -39,6 +39,8 @@ import { import { exec } from './exec'; +const escapedPathToNode = Path.sep === '\\' ? '\\\\node.exe' : '/node'; + const testWriter = new ToolingLogCollectingWriter(); const log = new ToolingLog(); log.setWriters([testWriter]); @@ -59,7 +61,7 @@ it('executes a command, logs the command, and logs the output', async () => { await exec(log, process.execPath, ['-e', 'console.log("hi")']); expect(testWriter.messages).toMatchInlineSnapshot(` Array [ - " debg $ /node -e console.log(\\"hi\\")", + " debg $ ${escapedPathToNode} -e console.log(\\"hi\\")", " debg hi", ] `); @@ -71,7 +73,7 @@ it('logs using level: option', async () => { }); expect(testWriter.messages).toMatchInlineSnapshot(` Array [ - " info $ /node -e console.log(\\"hi\\")", + " info $ ${escapedPathToNode} -e console.log(\\"hi\\")", " info hi", ] `); diff --git a/src/dev/build/lib/fs.ts b/src/dev/build/lib/fs.ts index ae846ef7d670..53fc241f7722 100644 --- a/src/dev/build/lib/fs.ts +++ b/src/dev/build/lib/fs.ts @@ -36,6 +36,7 @@ import { createGunzip } from 'zlib'; import { inspect, promisify } from 'util'; import archiver from 'archiver'; +import * as StreamZip from 'node-stream-zip'; import vfs from 'vinyl-fs'; import File from 'vinyl'; import del from 'del'; @@ -183,7 +184,7 @@ export async function copyAll( destination: string, options: CopyAllOptions = {} ) { - const { select = ['**/*'], dot = false, time = Date.now() } = options; + const { select = ['**/*'], dot = false, time = Date.now() / 1000 } = options; assertAbsolute(sourceDir); assertAbsolute(destination); @@ -266,6 +267,38 @@ export async function gunzip(source: string, destination: string) { ); } +interface UnzipOptions { + strip?: boolean | number; +} + +export async function unzip(source: string, destination: string, options: UnzipOptions) { + assertAbsolute(source); + assertAbsolute(destination); + + await mkdirAsync(destination, { recursive: true }); + + const zip = new StreamZip.async({ file: source }); + + if (!options.strip || !isFinite(options.strip as number)) { + // Extract the entire archive + await zip.extract(null, destination); + } else { + const stripLevels = options.strip === true ? 1 : options.strip; + + // Find the directories that are `stripLevels` deep and extract them only + for (const entry of Object.values(await zip.entries())) { + if (!entry.isDirectory) continue; + + const pathDepth = entry.name.replace(/\/+$/, '').split('/').length; + if (stripLevels === pathDepth) { + await zip.extract(entry.name, destination); + } + } + } + + await zip.close(); +} + interface CompressTarOptions { createRootDirectory: boolean; source: string; @@ -325,3 +358,7 @@ export async function compressZip({ return fileCount; } + +export function normalizePath(loc: string) { + return sep === '\\' ? loc.replace(/\\/g, '/') : loc; +} diff --git a/src/dev/build/lib/platform.ts b/src/dev/build/lib/platform.ts index 6553bcd3b11b..673356ec6205 100644 --- a/src/dev/build/lib/platform.ts +++ b/src/dev/build/lib/platform.ts @@ -35,6 +35,7 @@ export interface TargetPlatforms { darwin: boolean; linuxArm: boolean; linux: boolean; + windows: boolean; } export class Platform { diff --git a/src/dev/build/tasks/clean_tasks.ts b/src/dev/build/tasks/clean_tasks.ts index 8b1d635cdde6..c420a6b36b2c 100644 --- a/src/dev/build/tasks/clean_tasks.ts +++ b/src/dev/build/tasks/clean_tasks.ts @@ -30,7 +30,7 @@ import minimatch from 'minimatch'; -import { deleteAll, deleteEmptyFolders, scanDelete, Task, GlobalTask } from '../lib'; +import { deleteAll, deleteEmptyFolders, scanDelete, Task, GlobalTask, normalizePath } from '../lib'; export const Clean: GlobalTask = { global: true, @@ -190,8 +190,8 @@ export const CleanExtraBinScripts: Task = { if (platform.isWindows()) { await deleteAll( [ - build.resolvePathForPlatform(platform, 'bin', '*'), - `!${build.resolvePathForPlatform(platform, 'bin', '*.bat')}`, + normalizePath(build.resolvePathForPlatform(platform, 'bin', '*')), + `!${normalizePath(build.resolvePathForPlatform(platform, 'bin', '*.bat'))}`, ], log ); diff --git a/src/dev/build/tasks/nodejs/clean_node_builds_task.ts b/src/dev/build/tasks/nodejs/clean_node_builds_task.ts index 490d71e6d70d..938f7f43f692 100644 --- a/src/dev/build/tasks/nodejs/clean_node_builds_task.ts +++ b/src/dev/build/tasks/nodejs/clean_node_builds_task.ts @@ -28,7 +28,7 @@ * under the License. */ -import { deleteAll, Task } from '../../lib'; +import { deleteAll, normalizePath, Task } from '../../lib'; export const CleanNodeBuilds: Task = { description: 'Cleaning npm from node', @@ -37,9 +37,11 @@ export const CleanNodeBuilds: Task = { for (const platform of config.getTargetPlatforms()) { await deleteAll( [ - build.resolvePathForPlatform(platform, 'node/lib/node_modules'), - build.resolvePathForPlatform(platform, 'node/bin/npm'), - build.resolvePathForPlatform(platform, 'node/bin/npx'), + normalizePath(build.resolvePathForPlatform(platform, 'node/**/node_modules')), + normalizePath(build.resolvePathForPlatform(platform, 'node/**/npm*')), + normalizePath(build.resolvePathForPlatform(platform, 'node/**/npx*')), + normalizePath(build.resolvePathForPlatform(platform, 'node/**/corepack*')), + normalizePath(build.resolvePathForPlatform(platform, 'node/**/nodevars*')), ], log ); diff --git a/src/dev/build/tasks/nodejs/extract_node_builds_task.test.ts b/src/dev/build/tasks/nodejs/extract_node_builds_task.test.ts index 73e23ecdf270..6b3a066a1d2d 100644 --- a/src/dev/build/tasks/nodejs/extract_node_builds_task.test.ts +++ b/src/dev/build/tasks/nodejs/extract_node_builds_task.test.ts @@ -69,6 +69,7 @@ async function setup() { linux: false, linuxArm: false, darwin: false, + windows: false, }, }); @@ -101,15 +102,6 @@ it('runs expected fs operations', async () => { expect(usedMethods).toMatchInlineSnapshot(` Object { - "copy": Array [ - Array [ - /.node_binaries//node.exe, - /.node_binaries//win32-x64/node.exe, - Object { - "clone": true, - }, - ], - ], "untar": Array [ Array [ /.node_binaries//node-v-linux-x64.tar.gz, @@ -133,6 +125,15 @@ it('runs expected fs operations', async () => { }, ], ], + "unzip": Array [ + Array [ + /.node_binaries//node-v-win-x64.zip, + /.node_binaries//win32-x64, + Object { + "strip": 1, + }, + ], + ], } `); }); diff --git a/src/dev/build/tasks/nodejs/extract_node_builds_task.ts b/src/dev/build/tasks/nodejs/extract_node_builds_task.ts index 8e915a8b4e4b..8252ce2153f5 100644 --- a/src/dev/build/tasks/nodejs/extract_node_builds_task.ts +++ b/src/dev/build/tasks/nodejs/extract_node_builds_task.ts @@ -28,9 +28,7 @@ * under the License. */ -import Path from 'path'; - -import { untar, GlobalTask, copy } from '../../lib'; +import { untar, unzip, GlobalTask } from '../../lib'; import { getNodeDownloadInfo } from './node_download_info'; export const ExtractNodeBuilds: GlobalTask = { @@ -41,10 +39,7 @@ export const ExtractNodeBuilds: GlobalTask = { config.getTargetPlatforms().map(async (platform) => { const { downloadPath, extractDir } = getNodeDownloadInfo(config, platform); if (platform.isWindows()) { - // windows executable is not extractable, it's just an .exe file - await copy(downloadPath, Path.resolve(extractDir, 'node.exe'), { - clone: true, - }); + await unzip(downloadPath, extractDir, { strip: 1 }); } else { await untar(downloadPath, extractDir, { strip: 1 }); } diff --git a/src/dev/build/tasks/nodejs/node_download_info.ts b/src/dev/build/tasks/nodejs/node_download_info.ts index 5b9006e89f70..86e0c680ab0d 100644 --- a/src/dev/build/tasks/nodejs/node_download_info.ts +++ b/src/dev/build/tasks/nodejs/node_download_info.ts @@ -37,7 +37,7 @@ export function getNodeDownloadInfo(config: Config, platform: Platform) { const arch = platform.getNodeArch(); const downloadName = platform.isWindows() - ? 'win-x64/node.exe' + ? `node-v${version}-win-x64.zip` : `node-v${version}-${arch}.tar.gz`; const url = `https://nodejs.org/dist/v${version}/${downloadName}`; diff --git a/src/plugins/telemetry/server/collectors/usage/telemetry_usage_collector.test.ts b/src/plugins/telemetry/server/collectors/usage/telemetry_usage_collector.test.ts index 2cffae202a14..7e49c7d32445 100644 --- a/src/plugins/telemetry/server/collectors/usage/telemetry_usage_collector.test.ts +++ b/src/plugins/telemetry/server/collectors/usage/telemetry_usage_collector.test.ts @@ -51,8 +51,15 @@ describe('telemetry_usage_collector', () => { unreadable: resolve(tempDir, 'tests-telemetry_usage_collector-unreadable.yml'), valid: resolve(tempDir, 'telemetry.yml'), }; - const invalidFiles = [tempFiles.too_big, tempFiles.unreadable]; + const invalidFiles = [tempFiles.too_big]; const validFiles = [tempFiles.blank, tempFiles.empty, tempFiles.valid]; + // Windows cannot create the `unreadable` file as unreadable + if (process.platform === 'win32') { + validFiles.push(tempFiles.unreadable); + } else { + invalidFiles.push(tempFiles.unreadable); + } + const allFiles = Object.values(tempFiles); const expectedObject = { expected: 'value', @@ -98,7 +105,7 @@ describe('telemetry_usage_collector', () => { }); test('returns `true` file that has valid data', async () => { - expect(allFiles.filter(isFileReadable)).toEqual(validFiles); + expect(allFiles.filter(isFileReadable).sort()).toEqual(validFiles.sort()); }); }); diff --git a/src/plugins/url_forwarding/public/forward_app/normalize_path.ts b/src/plugins/url_forwarding/public/forward_app/normalize_path.ts index 88f3a1d53357..aae41809d76b 100644 --- a/src/plugins/url_forwarding/public/forward_app/normalize_path.ts +++ b/src/plugins/url_forwarding/public/forward_app/normalize_path.ts @@ -28,11 +28,13 @@ * under the License. */ -import { normalize } from 'path'; +import { normalize, posix } from 'path'; export function normalizePath(path: string) { + // `normalize` in path-browserify is an implementation of `posix.normalize` + const normalizeFunc = posix?.normalize || normalize; // resolve ../ within the path - const normalizedPath = normalize(path); + const normalizedPath = normalizeFunc(path); // strip any leading slashes and dots and replace with single leading slash return normalizedPath.replace(/(\.?\.?\/?)*/, '/'); } diff --git a/test/interpreter_functional/plugins/osd_tp_run_pipeline/package.json b/test/interpreter_functional/plugins/osd_tp_run_pipeline/package.json index 80275e41e042..45476309224d 100644 --- a/test/interpreter_functional/plugins/osd_tp_run_pipeline/package.json +++ b/test/interpreter_functional/plugins/osd_tp_run_pipeline/package.json @@ -9,7 +9,7 @@ "license": "Apache-2.0", "scripts": { "osd": "node ../../../../scripts/osd.js", - "build": "rm -rf './target' && tsc" + "build": "node ../../../../scripts/remove.js './target' && tsc" }, "devDependencies": { "@elastic/eui": "npm:@opensearch-project/oui@1.0.0", diff --git a/test/plugin_functional/plugins/app_link_test/package.json b/test/plugin_functional/plugins/app_link_test/package.json index 8b28e62e31b7..dd07b4de638c 100644 --- a/test/plugin_functional/plugins/app_link_test/package.json +++ b/test/plugin_functional/plugins/app_link_test/package.json @@ -9,7 +9,7 @@ "license": "Apache-2.0", "scripts": { "osd": "node ../../../../scripts/osd.js", - "build": "rm -rf './target' && tsc" + "build": "node ../../../../scripts/remove.js './target' && tsc" }, "devDependencies": { "typescript": "4.0.2" diff --git a/test/plugin_functional/plugins/core_app_status/package.json b/test/plugin_functional/plugins/core_app_status/package.json index 0304da467b46..524e33d8dfb2 100644 --- a/test/plugin_functional/plugins/core_app_status/package.json +++ b/test/plugin_functional/plugins/core_app_status/package.json @@ -9,7 +9,7 @@ "license": "Apache-2.0", "scripts": { "osd": "node ../../../../scripts/osd.js", - "build": "rm -rf './target' && tsc" + "build": "node ../../../../scripts/remove.js './target' && tsc" }, "devDependencies": { "typescript": "4.0.2" diff --git a/test/plugin_functional/plugins/core_plugin_a/package.json b/test/plugin_functional/plugins/core_plugin_a/package.json index 53ea6306f2a1..b57d5783c77e 100644 --- a/test/plugin_functional/plugins/core_plugin_a/package.json +++ b/test/plugin_functional/plugins/core_plugin_a/package.json @@ -9,7 +9,7 @@ "license": "Apache-2.0", "scripts": { "osd": "node ../../../../scripts/osd.js", - "build": "rm -rf './target' && tsc" + "build": "node ../../../../scripts/remove.js './target' && tsc" }, "devDependencies": { "typescript": "4.0.2" diff --git a/test/plugin_functional/plugins/core_plugin_appleave/package.json b/test/plugin_functional/plugins/core_plugin_appleave/package.json index 69e7caea397e..5caa1a70f8d2 100644 --- a/test/plugin_functional/plugins/core_plugin_appleave/package.json +++ b/test/plugin_functional/plugins/core_plugin_appleave/package.json @@ -9,7 +9,7 @@ "license": "Apache-2.0", "scripts": { "osd": "node ../../../../scripts/osd.js", - "build": "rm -rf './target' && tsc" + "build": "node ../../../../scripts/remove.js './target' && tsc" }, "devDependencies": { "typescript": "4.0.2" diff --git a/test/plugin_functional/plugins/core_plugin_b/package.json b/test/plugin_functional/plugins/core_plugin_b/package.json index 56ec66f867f8..d37ffd582e6d 100644 --- a/test/plugin_functional/plugins/core_plugin_b/package.json +++ b/test/plugin_functional/plugins/core_plugin_b/package.json @@ -9,7 +9,7 @@ "license": "Apache-2.0", "scripts": { "osd": "node ../../../../scripts/osd.js", - "build": "rm -rf './target' && tsc" + "build": "node ../../../../scripts/remove.js './target' && tsc" }, "devDependencies": { "typescript": "4.0.2" diff --git a/test/plugin_functional/plugins/core_plugin_chromeless/package.json b/test/plugin_functional/plugins/core_plugin_chromeless/package.json index 33a247924d08..0c444aaf80ca 100644 --- a/test/plugin_functional/plugins/core_plugin_chromeless/package.json +++ b/test/plugin_functional/plugins/core_plugin_chromeless/package.json @@ -9,7 +9,7 @@ "license": "Apache-2.0", "scripts": { "osd": "node ../../../../scripts/osd.js", - "build": "rm -rf './target' && tsc" + "build": "node ../../../../scripts/remove.js './target' && tsc" }, "devDependencies": { "typescript": "4.0.2" diff --git a/test/plugin_functional/plugins/core_plugin_route_timeouts/package.json b/test/plugin_functional/plugins/core_plugin_route_timeouts/package.json index 974d9398dd65..1b03b60ad387 100644 --- a/test/plugin_functional/plugins/core_plugin_route_timeouts/package.json +++ b/test/plugin_functional/plugins/core_plugin_route_timeouts/package.json @@ -9,7 +9,7 @@ "license": "Apache-2.0", "scripts": { "osd": "node ../../../../scripts/osd.js", - "build": "rm -rf './target' && tsc" + "build": "node ../../../../scripts/remove.js './target' && tsc" }, "devDependencies": { "typescript": "4.0.2" diff --git a/test/plugin_functional/plugins/core_plugin_static_assets/package.json b/test/plugin_functional/plugins/core_plugin_static_assets/package.json index 5b50b579549b..e44a09af12cb 100644 --- a/test/plugin_functional/plugins/core_plugin_static_assets/package.json +++ b/test/plugin_functional/plugins/core_plugin_static_assets/package.json @@ -9,7 +9,7 @@ "license": "Apache-2.0", "scripts": { "osd": "node ../../../../scripts/osd.js", - "build": "rm -rf './target' && tsc" + "build": "node ../../../../scripts/remove.js './target' && tsc" }, "devDependencies": { "typescript": "4.0.2" diff --git a/test/plugin_functional/plugins/core_provider_plugin/package.json b/test/plugin_functional/plugins/core_provider_plugin/package.json index 068d9b0e638d..778d9363e71d 100644 --- a/test/plugin_functional/plugins/core_provider_plugin/package.json +++ b/test/plugin_functional/plugins/core_provider_plugin/package.json @@ -9,7 +9,7 @@ "license": "Apache-2.0", "scripts": { "osd": "node ../../../../scripts/osd.js", - "build": "rm -rf './target' && tsc" + "build": "node ../../../../scripts/remove.js './target' && tsc" }, "devDependencies": { "typescript": "4.0.2" diff --git a/test/plugin_functional/plugins/data_search/package.json b/test/plugin_functional/plugins/data_search/package.json index fcd6ba5260f4..056a79f2139a 100644 --- a/test/plugin_functional/plugins/data_search/package.json +++ b/test/plugin_functional/plugins/data_search/package.json @@ -7,7 +7,7 @@ "license": "Apache-2.0", "scripts": { "osd": "node ../../../../scripts/osd.js", - "build": "rm -rf './target' && tsc" + "build": "node ../../../../scripts/remove.js './target' && tsc" }, "devDependencies": { "typescript": "4.0.2" diff --git a/test/plugin_functional/plugins/doc_views_links_plugin/package.json b/test/plugin_functional/plugins/doc_views_links_plugin/package.json index 92cfca078156..7cc258622ae8 100644 --- a/test/plugin_functional/plugins/doc_views_links_plugin/package.json +++ b/test/plugin_functional/plugins/doc_views_links_plugin/package.json @@ -9,9 +9,9 @@ "license": "Apache-2.0", "scripts": { "osd": "node ../../../../scripts/osd.js", - "build": "rm -rf './target' && tsc" + "build": "node ../../../../scripts/remove.js './target' && tsc" }, "devDependencies": { "typescript": "4.0.2" } -} \ No newline at end of file +} diff --git a/test/plugin_functional/plugins/doc_views_plugin/package.json b/test/plugin_functional/plugins/doc_views_plugin/package.json index 4f0aa8b8ae45..67018cec9d95 100644 --- a/test/plugin_functional/plugins/doc_views_plugin/package.json +++ b/test/plugin_functional/plugins/doc_views_plugin/package.json @@ -9,7 +9,7 @@ "license": "Apache-2.0", "scripts": { "osd": "node ../../../../scripts/osd.js", - "build": "rm -rf './target' && tsc" + "build": "node ../../../../scripts/remove.js './target' && tsc" }, "devDependencies": { "typescript": "4.0.2" diff --git a/test/plugin_functional/plugins/index_patterns/package.json b/test/plugin_functional/plugins/index_patterns/package.json index 114131058ece..3b88f3bf3932 100644 --- a/test/plugin_functional/plugins/index_patterns/package.json +++ b/test/plugin_functional/plugins/index_patterns/package.json @@ -9,7 +9,7 @@ "license": "Apache-2.0", "scripts": { "osd": "node ../../../../scripts/osd.js", - "build": "rm -rf './target' && tsc" + "build": "node ../../../../scripts/remove.js './target' && tsc" }, "devDependencies": { "typescript": "4.0.2" diff --git a/test/plugin_functional/plugins/management_test_plugin/package.json b/test/plugin_functional/plugins/management_test_plugin/package.json index cd0b7eb62b8d..b20971f403aa 100644 --- a/test/plugin_functional/plugins/management_test_plugin/package.json +++ b/test/plugin_functional/plugins/management_test_plugin/package.json @@ -9,7 +9,7 @@ "license": "Apache-2.0", "scripts": { "osd": "node ../../../../scripts/osd.js", - "build": "rm -rf './target' && tsc" + "build": "node ../../../../scripts/remove.js './target' && tsc" }, "devDependencies": { "typescript": "4.0.2" diff --git a/test/plugin_functional/plugins/opensearch_client_plugin/package.json b/test/plugin_functional/plugins/opensearch_client_plugin/package.json index fc7aab14306b..77d31a85f8f5 100644 --- a/test/plugin_functional/plugins/opensearch_client_plugin/package.json +++ b/test/plugin_functional/plugins/opensearch_client_plugin/package.json @@ -7,7 +7,7 @@ "license": "Apache-2.0", "scripts": { "osd": "node ../../../../scripts/osd.js", - "build": "rm -rf './target' && tsc" + "build": "node ../../../../scripts/remove.js './target' && tsc" }, "devDependencies": { "typescript": "4.0.2" diff --git a/test/plugin_functional/plugins/osd_sample_panel_action/package.json b/test/plugin_functional/plugins/osd_sample_panel_action/package.json index b1847e7d35f5..34ebf31d78f6 100644 --- a/test/plugin_functional/plugins/osd_sample_panel_action/package.json +++ b/test/plugin_functional/plugins/osd_sample_panel_action/package.json @@ -9,7 +9,7 @@ "license": "Apache-2.0", "scripts": { "osd": "node ../../../../scripts/osd.js", - "build": "rm -rf './target' && tsc" + "build": "node ../../../../scripts/remove.js './target' && tsc" }, "devDependencies": { "@elastic/eui": "npm:@opensearch-project/oui@1.0.0", diff --git a/test/plugin_functional/plugins/osd_top_nav/package.json b/test/plugin_functional/plugins/osd_top_nav/package.json index 49076bfe6261..a1a244da27cd 100644 --- a/test/plugin_functional/plugins/osd_top_nav/package.json +++ b/test/plugin_functional/plugins/osd_top_nav/package.json @@ -9,7 +9,7 @@ "license": "Apache-2.0", "scripts": { "osd": "node ../../../../scripts/osd.js", - "build": "rm -rf './target' && tsc" + "build": "node ../../../../scripts/remove.js './target' && tsc" }, "devDependencies": { "typescript": "4.0.2" diff --git a/test/plugin_functional/plugins/osd_tp_custom_visualizations/package.json b/test/plugin_functional/plugins/osd_tp_custom_visualizations/package.json index e1f3698fdd38..18961a35fda4 100644 --- a/test/plugin_functional/plugins/osd_tp_custom_visualizations/package.json +++ b/test/plugin_functional/plugins/osd_tp_custom_visualizations/package.json @@ -9,7 +9,7 @@ "license": "Apache-2.0", "scripts": { "osd": "node ../../../../scripts/osd.js", - "build": "rm -rf './target' && tsc" + "build": "node ../../../../scripts/remove.js './target' && tsc" }, "devDependencies": { "@elastic/eui": "npm:@opensearch-project/oui@1.0.0", diff --git a/test/plugin_functional/plugins/rendering_plugin/package.json b/test/plugin_functional/plugins/rendering_plugin/package.json index bb651872f1aa..2548cfef508e 100644 --- a/test/plugin_functional/plugins/rendering_plugin/package.json +++ b/test/plugin_functional/plugins/rendering_plugin/package.json @@ -9,7 +9,7 @@ "license": "Apache-2.0", "scripts": { "osd": "node ../../../../scripts/osd.js", - "build": "rm -rf './target' && tsc" + "build": "node ../../../../scripts/remove.js './target' && tsc" }, "devDependencies": { "typescript": "4.0.2" diff --git a/test/plugin_functional/plugins/ui_settings_plugin/package.json b/test/plugin_functional/plugins/ui_settings_plugin/package.json index f167bfc69946..db9bedec26d0 100644 --- a/test/plugin_functional/plugins/ui_settings_plugin/package.json +++ b/test/plugin_functional/plugins/ui_settings_plugin/package.json @@ -9,7 +9,7 @@ "license": "Apache-2.0", "scripts": { "osd": "node ../../../../scripts/osd.js", - "build": "rm -rf './target' && tsc" + "build": "node ../../scripts/remove.js './target' && tsc" }, "devDependencies": { "typescript": "4.0.2" diff --git a/yarn.lock b/yarn.lock index 2c8df6850b10..42a7660cf0be 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13319,6 +13319,11 @@ node-releases@^2.0.2: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.2.tgz#7139fe71e2f4f11b47d4d2986aaf8c48699e0c01" integrity sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg== +node-stream-zip@^1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/node-stream-zip/-/node-stream-zip-1.15.0.tgz#158adb88ed8004c6c49a396b50a6a5de3bca33ea" + integrity sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw== + nopt@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/nopt/-/nopt-2.2.1.tgz#2aa09b7d1768487b3b89a9c5aa52335bff0baea7" @@ -16102,7 +16107,7 @@ sisteransi@^1.0.5: slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" - integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= + integrity sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg== slash@^2.0.0: version "2.0.0"