diff --git a/packages/zowe-explorer/__tests__/__unit__/uss/ZoweUSSNode.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/uss/ZoweUSSNode.unit.test.ts index 678149792a..3d35630c6d 100644 --- a/packages/zowe-explorer/__tests__/__unit__/uss/ZoweUSSNode.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/uss/ZoweUSSNode.unit.test.ts @@ -11,6 +11,7 @@ import * as vscode from "vscode"; import * as zowe from "@zowe/cli"; +import * as unixActions from "../../../src/uss/actions"; import { Gui, ValidProfileEnum } from "@zowe/zowe-explorer-api"; import { ZoweExplorerApiRegister } from "../../../src/ZoweExplorerApiRegister"; import { Profiles } from "../../../src/Profiles"; @@ -33,6 +34,7 @@ import * as globals from "../../../src/globals"; import * as ussUtils from "../../../src/uss/utils"; import { ZoweLogger } from "../../../src/utils/LoggerUtils"; import { ZoweLocalStorage } from "../../../src/utils/ZoweLocalStorage"; +import { LocalFileManagement } from "../../../src/utils/LocalFileManagement"; jest.mock("fs"); jest.mock("path"); @@ -1070,15 +1072,13 @@ describe("ZoweUSSNode Unit Tests - Function node.openUSS()", () => { false, globalMocks.profileOne.name ); - - const isBinSpy = jest.spyOn(globalMocks.ussApi, "isFileTagBinOrAscii"); globalMocks.existsSync.mockReturnValue(null); // Tests that correct file is downloaded await node.openUSS(false, true, blockMocks.testUSSTree); expect(globalMocks.existsSync.mock.calls.length).toBe(1); expect(globalMocks.existsSync.mock.calls[0][0]).toBe(path.join(globals.USS_DIR, node.mProfileName || "", node.fullPath)); - expect(globalMocks.setStatusBarMessage).toBeCalledWith("$(sync~spin) Opening USS file..."); + expect(globalMocks.setStatusBarMessage).toBeCalledWith("$(sync~spin) Downloading USS file..."); // Tests that correct file is opened in editor globalMocks.withProgress(globalMocks.downloadUSSFile); @@ -1115,15 +1115,13 @@ describe("ZoweUSSNode Unit Tests - Function node.openUSS()", () => { false, globalMocks.profileOne.name ); - - const isBinSpy = jest.spyOn(globalMocks.ussApi, "isFileTagBinOrAscii"); globalMocks.existsSync.mockReturnValue(null); // Tests that correct file is downloaded await node.openUSS(false, true, blockMocks.testUSSTree); expect(globalMocks.existsSync.mock.calls.length).toBe(1); expect(globalMocks.existsSync.mock.calls[0][0]).toBe(path.join(globals.USS_DIR, node.mProfileName || "", node.fullPath)); - expect(globalMocks.setStatusBarMessage).toBeCalledWith("$(sync~spin) Opening USS file..."); + expect(globalMocks.setStatusBarMessage).toBeCalledWith("$(sync~spin) Downloading USS file..."); // Tests that correct file is opened in editor globalMocks.withProgress(globalMocks.downloadUSSFile); expect(globalMocks.withProgress).toBeCalledWith(globalMocks.downloadUSSFile); @@ -1141,16 +1139,19 @@ describe("ZoweUSSNode Unit Tests - Function node.openUSS()", () => { "parent", vscode.TreeItemCollapsibleState.Collapsed, blockMocks.ussNode, - null, + null as any, "/", false, globalMocks.profileOne.name ); const child = new ZoweUSSNode("child", vscode.TreeItemCollapsibleState.None, parent, null, "/parent", false, globalMocks.profileOne.name); - - globalMocks.existsSync.mockReturnValue("exists"); + child.binary = false; + const mockFileInfo = { + name: child.label, + path: path.join(globals.USS_DIR, child.mProfileName || "", child.fullPath), + }; + Object.defineProperty(LocalFileManagement, "downloadUnixFile", { value: jest.fn().mockResolvedValueOnce(mockFileInfo), configurable: true }); globalMocks.mockShowTextDocument.mockRejectedValueOnce(Error("testError")); - globalMocks.fileExistsCaseSensitveSync.mockReturnValue(true); try { await child.openUSS(false, true, blockMocks.testUSSTree); @@ -1158,9 +1159,8 @@ describe("ZoweUSSNode Unit Tests - Function node.openUSS()", () => { // Prevent exception from failing test } - expect(globalMocks.ussFile.mock.calls.length).toBe(0); expect(globalMocks.openTextDocument.mock.calls.length).toBe(1); - expect(globalMocks.openTextDocument.mock.calls[0][0]).toBe(child.getUSSDocumentFilePath()); + expect(globalMocks.openTextDocument.mock.calls[0][0]).toBe(path.join(globals.USS_DIR, child.mProfileName || "", child.fullPath)); expect(globalMocks.mockShowTextDocument.mock.calls.length).toBe(1); expect(globalMocks.showErrorMessage.mock.calls.length).toBe(1); expect(globalMocks.showErrorMessage.mock.calls[0][0]).toBe("Error: testError"); @@ -1275,7 +1275,7 @@ describe("ZoweUSSNode Unit Tests - Function node.openUSS()", () => { await node.openUSS(false, true, blockMocks.testUSSTree); expect(globalMocks.existsSync.mock.calls.length).toBe(1); expect(globalMocks.existsSync.mock.calls[0][0]).toBe(path.join(globals.USS_DIR, node.getProfileName() || "", node.fullPath)); - expect(globalMocks.setStatusBarMessage).toBeCalledWith("$(sync~spin) Opening USS file..."); + expect(globalMocks.setStatusBarMessage).toBeCalledWith("$(sync~spin) Downloading USS file..."); // Make sure correct file is displayed in the editor globalMocks.withProgress(globalMocks.downloadUSSFile); expect(globalMocks.openTextDocument.mock.calls.length).toBe(1); diff --git a/packages/zowe-explorer/__tests__/__unit__/uss/actions.unit.test.ts b/packages/zowe-explorer/__tests__/__unit__/uss/actions.unit.test.ts index df0d8559e1..381e58d48f 100644 --- a/packages/zowe-explorer/__tests__/__unit__/uss/actions.unit.test.ts +++ b/packages/zowe-explorer/__tests__/__unit__/uss/actions.unit.test.ts @@ -41,6 +41,7 @@ import { ZoweLocalStorage } from "../../../src/utils/ZoweLocalStorage"; import * as wsUtils from "../../../src/utils/workspace"; import * as context from "../../../src/shared/context"; import { AttributeView } from "../../../src/uss/AttributeView"; +import { LocalFileManagement } from "../../../src/utils/LocalFileManagement"; jest.mock("../../../src/utils/LoggerUtils"); @@ -639,6 +640,8 @@ describe("USS Action Unit Tests - Function changeFileType", () => { const globalMocks = createGlobalMocks(); const blockMocks = await createBlockMocks(globalMocks); const node = new ZoweUSSNode("node", vscode.TreeItemCollapsibleState.None, blockMocks.ussNode, null, null); + Object.defineProperty(node, "getUSSDocumentFilePath", { value: jest.fn().mockReturnValueOnce(blockMocks.testDoc), configurable: true }); + Object.defineProperty(fs, "existsSync", { value: jest.fn().mockReturnValueOnce(false), configurable: true }); node.binary = true; node.contextValue = globals.DS_BINARY_FILE_CONTEXT; diff --git a/packages/zowe-explorer/src/uss/ZoweUSSNode.ts b/packages/zowe-explorer/src/uss/ZoweUSSNode.ts index 27cb48ca7a..7ea327bcc0 100644 --- a/packages/zowe-explorer/src/uss/ZoweUSSNode.ts +++ b/packages/zowe-explorer/src/uss/ZoweUSSNode.ts @@ -25,6 +25,7 @@ import { closeOpenedTextFile } from "../utils/workspace"; import * as nls from "vscode-nls"; import { UssFileTree, UssFileType, UssFileUtils } from "./FileStructure"; import { ZoweLogger } from "../utils/LoggerUtils"; +import { downloadUnixFile } from "./actions"; // Set up localization nls.config({ @@ -502,60 +503,15 @@ export class ZoweUSSNode extends ZoweTreeNode implements IZoweUSSTreeNode { const doubleClicked = Gui.utils.wasDoubleClicked(this, ussFileProvider); const shouldPreview = doubleClicked ? false : previewFile; - if (Profiles.getInstance().validProfile === ValidProfileEnum.VALID || Profiles.getInstance().validProfile === ValidProfileEnum.UNVERIFIED) { + if (Profiles.getInstance().validProfile !== ValidProfileEnum.INVALID) { try { - switch (true) { - // For opening favorited and non-favorited files - case this.getParent().contextValue === globals.FAV_PROFILE_CONTEXT: - break; - case contextually.isUssSession(this.getParent()): - break; - // Handle file path for files in directories and favorited directories - case contextually.isUssDirectory(this.getParent()): - break; - default: - Gui.errorMessage(localize("openUSS.error.invalidNode", "open() called from invalid node.")); - throw Error(localize("openUSS.error.invalidNode", "open() called from invalid node.")); - } - - const documentFilePath = this.getUSSDocumentFilePath(); - // check if some other file is already created with the same name avoid opening file warn user - const fileExists = fs.existsSync(documentFilePath); - if (fileExists && !fileExistsCaseSensitveSync(documentFilePath)) { - Gui.showMessage( - localize( - "openUSS.name.exists", - // eslint-disable-next-line max-len - "There is already a file with the same name. Please change your OS file system settings if you want to give case sensitive file names" - ) - ); - } else { - // if local copy exists, open that instead of pulling from mainframe - if (download || !fileExists) { - const cachedProfile = Profiles.getInstance().loadNamedProfile(this.getProfileName()); - const fullPath = this.fullPath; - const chooseBinary = - this.binary || (await ZoweExplorerApiRegister.getUssApi(cachedProfile).isFileTagBinOrAscii(this.fullPath)); - - const statusMsg = Gui.setStatusBarMessage(localize("ussFile.opening", "$(sync~spin) Opening USS file...")); - const response = await ZoweExplorerApiRegister.getUssApi(cachedProfile).getContents(fullPath, { - file: documentFilePath, - binary: chooseBinary, - returnEtag: true, - encoding: cachedProfile.profile?.encoding, - responseTimeout: cachedProfile.profile?.responseTimeout, - }); - statusMsg.dispose(); - this.downloaded = true; - this.setEtag(response.apiResponse.etag); - } - - // Add document name to recently-opened files - ussFileProvider.addFileHistory(`[${this.getProfile().name}]: ${this.fullPath}`); - ussFileProvider.getTreeView().reveal(this, { select: true, focus: true, expand: false }); + const fileInfo = await downloadUnixFile(this, download); + this.downloaded = true; + // Add document name to recently-opened files + ussFileProvider.addFileHistory(`[${this.getProfile().name}]: ${this.fullPath}`); + ussFileProvider.getTreeView().reveal(this, { select: true, focus: true, expand: false }); - await this.initializeFileOpening(documentFilePath, shouldPreview); - } + await this.initializeFileOpening(fileInfo.path, shouldPreview); } catch (err) { await errorHandling(err, this.mProfileName); throw err; diff --git a/packages/zowe-explorer/src/uss/actions.ts b/packages/zowe-explorer/src/uss/actions.ts index 301efd20f5..f1f79188da 100644 --- a/packages/zowe-explorer/src/uss/actions.ts +++ b/packages/zowe-explorer/src/uss/actions.ts @@ -14,7 +14,7 @@ import { imperative, IZosFilesResponse } from "@zowe/cli"; import * as fs from "fs"; import * as globals from "../globals"; import * as path from "path"; -import { concatChildNodes, uploadContent, getSelectedNodeList } from "../shared/utils"; +import { concatChildNodes, uploadContent, getSelectedNodeList, localFileInfo } from "../shared/utils"; import { errorHandling } from "../utils/ProfilesUtils"; import { Gui, ValidProfileEnum, IZoweTree, IZoweUSSTreeNode } from "@zowe/zowe-explorer-api"; import { Profiles } from "../Profiles"; @@ -501,3 +501,59 @@ export async function pasteUss(ussFileProvider: IZoweTree, nod const nodeToRefresh = node?.contextValue != null && contextually.isUssSession(node) ? selectedNode : selectedNode.getParent(); ussFileProvider.refreshElement(nodeToRefresh); } + +export async function downloadUnixFile(node: IZoweUSSTreeNode, download: boolean): Promise { + const fileInfo = {} as localFileInfo; + const errorMsg = localize("downloadUnixFile.invalidNode.error", "open() called from invalid node."); + switch (true) { + // For opening favorited and non-favorited files + case node.getParent().contextValue === globals.FAV_PROFILE_CONTEXT: + break; + case contextually.isUssSession(node.getParent()): + break; + // Handle file path for files in directories and favorited directories + case contextually.isUssDirectory(node.getParent()): + break; + default: + Gui.errorMessage(errorMsg); + throw Error(errorMsg); + } + + fileInfo.path = node.getUSSDocumentFilePath(); + fileInfo.name = String(node.label); + // check if some other file is already created with the same name avoid opening file warn user + const fileExists = fs.existsSync(fileInfo.path); + if (fileExists && !fileExistsCaseSensitveSync(fileInfo.path)) { + Gui.showMessage( + localize( + "downloadUnixFile.name.exists", + // eslint-disable-next-line max-len + "There is already a file with the same name. Please change your OS file system settings if you want to give case sensitive file names" + ) + ); + return; + } + // if local copy exists, open that instead of pulling from mainframe + if (download || !fileExists) { + try { + const cachedProfile = Profiles.getInstance().loadNamedProfile(node.getProfileName()); + const fullPath = node.fullPath; + const chooseBinary = node.binary || (await ZoweExplorerApiRegister.getUssApi(cachedProfile).isFileTagBinOrAscii(fullPath)); + + const statusMsg = Gui.setStatusBarMessage(localize("downloadUnixFile.downloading", "$(sync~spin) Downloading USS file...")); + const response = await ZoweExplorerApiRegister.getUssApi(cachedProfile).getContents(fullPath, { + file: fileInfo.path, + binary: chooseBinary, + returnEtag: true, + encoding: cachedProfile.profile?.encoding, + responseTimeout: cachedProfile.profile?.responseTimeout, + }); + statusMsg.dispose(); + node.setEtag(response.apiResponse.etag); + return fileInfo; + } catch (err) { + await errorHandling(err, this.mProfileName); + throw err; + } + } +} diff --git a/packages/zowe-explorer/src/utils/LocalFileManagement.ts b/packages/zowe-explorer/src/utils/LocalFileManagement.ts index 838d0d469a..9839a9cc9f 100644 --- a/packages/zowe-explorer/src/utils/LocalFileManagement.ts +++ b/packages/zowe-explorer/src/utils/LocalFileManagement.ts @@ -18,8 +18,9 @@ import { isTypeUssTreeNode } from "../shared/context"; import { ZoweExplorerApiRegister } from "../ZoweExplorerApiRegister"; import { ZoweLogger } from "./LoggerUtils"; import * as nls from "vscode-nls"; -import { isZoweDatasetTreeNode, isZoweUSSTreeNode } from "../shared/utils"; +import { isZoweDatasetTreeNode, isZoweUSSTreeNode, localFileInfo } from "../shared/utils"; import { downloadPs } from "../dataset/actions"; +import { downloadUnixFile } from "../uss/actions"; // Set up localization nls.config({ @@ -92,18 +93,15 @@ export class LocalFileManagement { } private static async getCompareFilePaths(node: IZoweTreeNode): Promise { - // ZoweLogger.info(`Getting files ${String(globals.filesToCompare[0].label)} and ${String(globals.filesToCompare[1].label)} for comparison.`); + ZoweLogger.info(`Getting files ${String(globals.filesToCompare[0].label)} and ${String(globals.filesToCompare[1].label)} for comparison.`); + let fileInfo = {} as localFileInfo; if (isZoweDatasetTreeNode(node)) { - const fileInfo = await downloadPs(node); - return fileInfo.path; + fileInfo = await downloadPs(node); } if (isZoweUSSTreeNode(node)) { - // do something with uss tree node - // documentFilePath = getUSSDocumentFilePath(node); - // if (!fs.existsSync(documentFilePath)) { - // await downloadUnixFile(node, documentFilePath); - // } + fileInfo = await downloadUnixFile(node, true); } + return fileInfo.path; // do something with job spool tree node // const uri = encodeJobFile(node.getProfile().name, (node as Spool).spool); @@ -113,6 +111,5 @@ export class LocalFileManagement { // // Fetch any changes to the spool file if it exists in the SpoolProvider // await spoolFile.fetchContent(); // } - return ""; } }