Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions src/make.ts
Original file line number Diff line number Diff line change
Expand Up @@ -456,8 +456,28 @@ export async function doBuildTarget(
try {
const quotingStlye: vscode.ShellQuoting = vscode.ShellQuoting.Strong;
const quotingStyleName: string = "Strong";

// Check if the terminal is using Cygwin/MSYS bash and convert paths accordingly
const usingCygwinBash = util.isWindowsTerminalUsingCygwinOrMsysBash();
let commandValue = configuration.getConfigurationMakeCommand();
let cwdValue: string = configuration.makeBaseDirectory();

if (usingCygwinBash) {
// Convert Windows paths to POSIX paths for Cygwin/MSYS bash compatibility
commandValue = util.windowsPathToPosix(commandValue);
cwdValue = util.windowsPathToPosix(cwdValue);
// Convert any path arguments (like -f makefile path)
makeArgs = makeArgs.map((arg) => {
// Check if the argument looks like a Windows absolute path
if (/^[A-Za-z]:[\\\/]/.test(arg)) {
return util.windowsPathToPosix(arg);
}
return arg;
});
}

let myTaskCommand: vscode.ShellQuotedString = {
value: configuration.getConfigurationMakeCommand(),
value: commandValue,
quoting: quotingStlye,
};
let myTaskArgs: vscode.ShellQuotedString[] = makeArgs.map((arg) => {
Expand Down Expand Up @@ -485,7 +505,7 @@ export async function doBuildTarget(
util.modifiedEnvironmentVariables as util.EnvironmentVariables
)
: undefined,
cwd,
cwd: cwdValue,
};

let shellExec: vscode.ShellExecution = new vscode.ShellExecution(
Expand Down
65 changes: 65 additions & 0 deletions src/test/fakeSuite/extension.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,71 @@ suite("Unit testing replacing characters in and outside of quotes", () => {
});
});

suite("Unit testing Windows to POSIX path conversion", () => {
suiteSetup(async function (this: Mocha.Context) {
this.timeout(100000);
});

setup(async function (this: Mocha.Context) {
this.timeout(100000);
});

test("Test windowsPathToPosix with absolute Windows paths", () => {
const tests = [
"C:\\cygwin64\\bin\\make.exe",
"D:\\projects\\myapp\\Makefile",
"c:\\Users\\user\\git\\project",
"E:/path/with/forward/slashes",
];
const expectedResults = [
"/cygdrive/c/cygwin64/bin/make.exe",
"/cygdrive/d/projects/myapp/Makefile",
"/cygdrive/c/Users/user/git/project",
"/cygdrive/e/path/with/forward/slashes",
];

for (let i = 0; i < tests.length; i++) {
expect(util.windowsPathToPosix(tests[i])).to.be.equal(expectedResults[i]);
}
});

test("Test windowsPathToPosix with already POSIX paths", () => {
const tests = [
"/usr/bin/make",
"/cygdrive/c/path/to/file",
"/home/user/project",
];
// POSIX paths should be returned unchanged
for (let i = 0; i < tests.length; i++) {
expect(util.windowsPathToPosix(tests[i])).to.be.equal(tests[i]);
}
});

test("Test windowsPathToPosix with relative paths", () => {
const tests = [
"relative\\path\\to\\file",
"..\\parent\\dir",
".\\current\\dir",
"just-a-filename.txt",
];
const expectedResults = [
"relative/path/to/file",
"../parent/dir",
"./current/dir",
"just-a-filename.txt",
];

for (let i = 0; i < tests.length; i++) {
expect(util.windowsPathToPosix(tests[i])).to.be.equal(expectedResults[i]);
}
});

test("Test windowsPathToPosix with empty and special cases", () => {
expect(util.windowsPathToPosix("")).to.be.equal("");
expect(util.windowsPathToPosix("make")).to.be.equal("make");
});
});

// TODO: refactor initialization and cleanup of each test
suite("Fake dryrun parsing", () => {
suiteSetup(async function (this: Mocha.Context) {
Expand Down
66 changes: 66 additions & 0 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,72 @@ export async function ensureWindowsPath(path: string): Promise<string> {
return winPath;
}

// Check if the default terminal shell on Windows is a Cygwin/MSYS bash.
// This is determined by looking at the terminal.integrated.defaultProfile.windows setting
// and checking if the corresponding profile uses a bash.exe from cygwin or msys paths.
export function isWindowsTerminalUsingCygwinOrMsysBash(): boolean {
if (process.platform !== "win32") {
return false;
}

const terminalConfig = vscode.workspace.getConfiguration("terminal");
const defaultProfileName = terminalConfig.get<string>(
"integrated.defaultProfile.windows"
);

if (!defaultProfileName) {
return false;
}

const profiles = terminalConfig.get<Record<string, { path?: string }>>(
"integrated.profiles.windows"
);

if (!profiles) {
return false;
}

const profile = profiles[defaultProfileName];
if (!profile || !profile.path) {
return false;
}

const shellPath = profile.path.toLowerCase();
// Check if the shell is a bash from cygwin or msys paths
return (
(shellPath.includes("cygwin") || shellPath.includes("msys")) &&
shellPath.endsWith("bash.exe")
);
}

// Convert a Windows path (C:\path\to\file) into a POSIX path for use with Cygwin/MSYS bash.
// This is the inverse of ensureWindowsPath.
// Example: C:\cygwin64\bin\make.exe -> /cygdrive/c/cygwin64/bin/make.exe
export function windowsPathToPosix(windowsPath: string): string {
if (!windowsPath) {
return windowsPath;
}

// Check if it's already a POSIX path
if (windowsPath.startsWith("/")) {
return windowsPath;
}

// Check if it's a Windows absolute path (e.g., C:\path or C:/path)
const windowsAbsolutePathRegex = /^([A-Za-z]):[\\\/]/;
const match = windowsPath.match(windowsAbsolutePathRegex);

if (match) {
const driveLetter = match[1].toLowerCase();
// Remove the drive letter and colon, replace backslashes with forward slashes
const restOfPath = windowsPath.substring(2).replace(/\\/g, "/");
return `/cygdrive/${driveLetter}${restOfPath}`;
}

// For relative paths or paths without a drive letter, just replace backslashes
return windowsPath.replace(/\\/g, "/");
}

// Helper to reinterpret one relative path (to the given current path) printed by make as full path
export async function makeFullPath(
relPath: string,
Expand Down