Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
090934b
[WSLC] Add --workdir / -w option to 'wslc exec'
Mar 27, 2026
4a2218d
Merge branch 'feature/wsl-for-apps' into user/ptrivedi/exec-workingdir
Mar 30, 2026
84851fd
Update test/windows/wslc/CommandLineTestCases.h
ptrivedi Mar 30, 2026
9add70a
Update test/windows/wslc/CommandLineTestCases.h
ptrivedi Mar 30, 2026
53c56a1
Merge branch 'feature/wsl-for-apps' into user/ptrivedi/exec-workingdir
ptrivedi Apr 2, 2026
ce1e458
Fix clang formatting issues
Apr 2, 2026
e6b90dd
Update test/windows/wslc/WSLCCLIExecutionUnitTests.cpp
ptrivedi Apr 2, 2026
1699085
Add E2E tests for wslc container exec, including --workdir option
Apr 2, 2026
d54748e
Fix clang formatting in WSLCE2EContainerExecTests.cpp
Apr 2, 2026
9e966e3
Validate --workdir is non-empty; add unit and parse test cases
Apr 2, 2026
6b8fcbc
Fix clang formatting in CommandLineTestCases.h
Apr 2, 2026
6267e6d
Trim exec E2E tests to --workdir coverage only
Apr 2, 2026
70d3f3a
Merge branch 'feature/wsl-for-apps' into user/ptrivedi/exec-workingdir
ptrivedi Apr 3, 2026
6eacc0b
Missed change from merge conflict resolution
Apr 3, 2026
0979c36
Fix --workdir whitespace validation to use std::iswspace for full Uni…
Copilot Apr 3, 2026
7c16de1
Use lambda with wint_t cast in iswspace call to avoid potential UB
Copilot Apr 3, 2026
a923420
Missed change from merge conflict resolution
Apr 3, 2026
a1e710e
Merge branch 'user/ptrivedi/exec-workingdir' of https://github.com/mi…
Apr 3, 2026
53b0bb9
Address Copilot PR feedback
Apr 4, 2026
edb9743
Merge branch 'feature/wsl-for-apps' into user/ptrivedi/exec-workingdir
ptrivedi Apr 4, 2026
2942cb4
Update src/windows/wslc/services/ContainerService.cpp
ptrivedi Apr 4, 2026
7e7fbfe
Fix ParserTest_StateMachine_PositionalForward: replace -v with -h in …
Apr 6, 2026
00e3420
Merge remote-tracking branch 'origin/feature/wsl-for-apps' into user/…
Apr 6, 2026
f7cda40
Fix E2E exec help test: add --user option after base branch merge
Apr 6, 2026
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
1 change: 1 addition & 0 deletions src/windows/wslc/arguments/ArgumentDefinitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ _(TTY, "tty", L"t", Kind::Flag, L
_(User, "user", L"u", Kind::Value, L"User ID for the process (name|uid|uid:gid)") \
_(Verbose, "verbose", L"v", Kind::Flag, L"Output verbose details") \
_(Version, "version", L"v", Kind::Flag, L"Show version information for this tool") \
_(WorkDir, "workdir", L"w", Kind::Value, L"Working directory inside the container") \
_(Virtual, "virtualization", NO_ALIAS, Kind::Value, L"Expose virtualization capabilities to the container") \
_(Volume, "volume", L"v", Kind::Value, L"Bind mount a volume to the container") \
// clang-format on
1 change: 1 addition & 0 deletions src/windows/wslc/commands/ContainerExecCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ std::vector<Argument> ContainerExecCommand::GetArguments() const
Argument::Create(ArgType::Session),
Argument::Create(ArgType::TTY),
Argument::Create(ArgType::User),
Argument::Create(ArgType::WorkDir),
};
}

Expand Down
1 change: 1 addition & 0 deletions src/windows/wslc/services/ContainerModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ struct ContainerOptions
bool TTY = false;
std::vector<std::string> Ports;
std::vector<std::wstring> Volumes;
std::string WorkingDirectory;
std::vector<std::string> Entrypoint;
};

Expand Down
9 changes: 7 additions & 2 deletions src/windows/wslc/services/ContainerService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,9 +354,14 @@ int ContainerService::Exec(Session& session, const std::string& id, ContainerOpt
WI_SetFlagIf(execFlags, WSLCProcessFlagsStdin, options.Interactive);
WI_SetFlagIf(execFlags, WSLCProcessFlagsTty, options.TTY);

wsl::windows::common::WSLCProcessLauncher launcher({}, options.Arguments, options.EnvironmentVariables, execFlags);
if (!options.WorkingDirectory.empty())
{
launcher.SetWorkingDirectory(std::move(options.WorkingDirectory));
}

ConsoleService consoleService;
return consoleService.AttachToCurrentConsole(
wsl::windows::common::WSLCProcessLauncher({}, options.Arguments, options.EnvironmentVariables, execFlags).Launch(*container));
return consoleService.AttachToCurrentConsole(launcher.Launch(*container));
}

InspectContainer ContainerService::Inspect(Session& session, const std::string& id)
Expand Down
5 changes: 5 additions & 0 deletions src/windows/wslc/tasks/ContainerTasks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,11 @@ void SetContainerOptionsFromArgs(CLIExecutionContext& context)
}
}

if (context.Args.Contains(ArgType::WorkDir))
{
options.WorkingDirectory = WideToMultiByte(context.Args.Get<ArgType::WorkDir>());
}

context.Data.Add<Data::ContainerOptions>(std::move(options));
}

Expand Down
4 changes: 4 additions & 0 deletions test/windows/wslc/CommandLineTestCases.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ COMMAND_LINE_TEST_CASE(L"container create --name foo ubuntu", L"create", true)
COMMAND_LINE_TEST_CASE(L"exec cont1 echo Hello", L"exec", true)
COMMAND_LINE_TEST_CASE(L"exec cont1", L"exec", false) // Missing required command argument
COMMAND_LINE_TEST_CASE(L"container exec -it cont1 sh -c \"echo a && echo b\"", L"exec", true) // docker exec example
COMMAND_LINE_TEST_CASE(L"exec cont1 --workdir /app echo Hello", L"exec", true)
COMMAND_LINE_TEST_CASE(L"exec cont1 -w /app echo Hello", L"exec", true)
COMMAND_LINE_TEST_CASE(L"container exec --workdir /app cont1 sh", L"exec", true)
COMMAND_LINE_TEST_CASE(L"exec cont1 --workdir", L"exec", false) // Missing value for --workdir
COMMAND_LINE_TEST_CASE(L"kill cont1 --signal sigkill", L"kill", true)
COMMAND_LINE_TEST_CASE(L"container kill cont1 -s KILL", L"kill", true)
COMMAND_LINE_TEST_CASE(L"inspect cont1", L"inspect", true)
Expand Down
58 changes: 58 additions & 0 deletions test/windows/wslc/WSLCCLIExecutionUnitTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ Module Name:

#include "Command.h"
#include "RootCommand.h"
#include "ContainerCommand.h"
#include "ContainerTasks.h"

using namespace wsl::windows::wslc;
using namespace WSLCTestHelpers;
Expand Down Expand Up @@ -116,6 +118,62 @@ class WSLCCLIExecutionUnitTests
// This one will just verify all the data types in the Data Map work as expected.
}

// Test: SetContainerOptionsFromArgs sets WorkingDirectory when --workdir is provided
TEST_METHOD(SetContainerOptionsFromArgs_WithWorkDir_SetsWorkingDirectory)
{
CLIExecutionContext context;
context.Args.Add<ArgType::WorkDir>(std::wstring{L"/app"});

wsl::windows::wslc::task::SetContainerOptionsFromArgs(context);

const auto& options = context.Data.Get<Data::ContainerOptions>();
VERIFY_ARE_EQUAL(std::string("/app"), options.WorkingDirectory);
}

// Test: SetContainerOptionsFromArgs leaves WorkingDirectory empty when --workdir is not provided
TEST_METHOD(SetContainerOptionsFromArgs_WithoutWorkDir_WorkingDirectoryIsEmpty)
{
CLIExecutionContext context;

wsl::windows::wslc::task::SetContainerOptionsFromArgs(context);

const auto& options = context.Data.Get<Data::ContainerOptions>();
VERIFY_IS_TRUE(options.WorkingDirectory.empty());
}

// Test: Full parse of 'exec --workdir /path cont1 cmd' sets WorkingDirectory
TEST_METHOD(ExecCommand_ParseWorkDirLongOption_SetsWorkingDirectory)
{
// Simulate the args that reach ContainerExecCommand after routing consumed "exec"
auto invocation = CreateInvocationFromCommandLine(L"wslc --workdir /tmp/mydir cont1 sh");

ContainerExecCommand command{L""};
CLIExecutionContext context;
command.ParseArguments(invocation, context.Args);
command.ValidateArguments(context.Args);

wsl::windows::wslc::task::SetContainerOptionsFromArgs(context);

const auto& options = context.Data.Get<Data::ContainerOptions>();
VERIFY_ARE_EQUAL(std::string("/tmp/mydir"), options.WorkingDirectory);
}

// Test: Full parse of 'exec -w /path cont1 cmd' (short alias) sets WorkingDirectory
TEST_METHOD(ExecCommand_ParseWorkDirShortOption_SetsWorkingDirectory)
{
auto invocation = CreateInvocationFromCommandLine(L"wslc -w /app cont1 sh");

ContainerExecCommand command{L""};
CLIExecutionContext context;
command.ParseArguments(invocation, context.Args);
command.ValidateArguments(context.Args);

wsl::windows::wslc::task::SetContainerOptionsFromArgs(context);

const auto& options = context.Data.Get<Data::ContainerOptions>();
VERIFY_ARE_EQUAL(std::string("/app"), options.WorkingDirectory);
}

// Test: Command Line test parsing all cases defined in CommandLineTestCases.h
// This test verifies the command line parsing logic used by the CLI and executes the same
// code as the CLI up to the point of command execution, including parsing and argument validtion.
Expand Down
Loading