Skip to content

Commit 7ecf97a

Browse files
committed
feat(cli): add dev session watcher
1 parent 45e57e2 commit 7ecf97a

7 files changed

Lines changed: 1181 additions & 0 deletions

File tree

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
*
3+
* @file DevChangeClassifier.hpp
4+
* @author Gaspard Kirira
5+
*
6+
* Copyright 2026, Gaspard Kirira. All rights reserved.
7+
* https://github.com/vixcpp/vix
8+
* Use of this source code is governed by a MIT license
9+
* that can be found in the License file.
10+
*
11+
* Vix.cpp
12+
*
13+
* Dev mode file change classifier
14+
*
15+
*/
16+
17+
#ifndef VIX_CLI_COMMANDS_RUN_DEV_DEV_CHANGE_CLASSIFIER_HPP
18+
#define VIX_CLI_COMMANDS_RUN_DEV_DEV_CHANGE_CLASSIFIER_HPP
19+
20+
#include <filesystem>
21+
#include <string>
22+
23+
namespace vix::commands::RunCommand::dev
24+
{
25+
namespace fs = std::filesystem;
26+
27+
enum class DevChangeKind
28+
{
29+
Ignore,
30+
RebuildOnly,
31+
ReconfigureAndRebuild
32+
};
33+
34+
std::string to_string(DevChangeKind kind);
35+
36+
class DevChangeClassifier
37+
{
38+
public:
39+
DevChangeClassifier() = default;
40+
41+
DevChangeKind classify(
42+
const fs::path &projectDir,
43+
const fs::path &changedPath) const;
44+
45+
private:
46+
bool should_ignore_path(
47+
const fs::path &projectDir,
48+
const fs::path &changedPath) const;
49+
50+
bool is_source_file(const fs::path &path) const;
51+
bool is_header_file(const fs::path &path) const;
52+
bool is_config_file(const fs::path &path) const;
53+
};
54+
55+
} // namespace vix::commands::RunCommand::dev
56+
57+
#endif // VIX_CLI_COMMANDS_RUN_DEV_DEV_CHANGE_CLASSIFIER_HPP
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/**
2+
*
3+
* @file DevRebuilder.hpp
4+
* @author Gaspard Kirira
5+
*
6+
* Copyright 2026, Gaspard Kirira. All rights reserved.
7+
* https://github.com/vixcpp/vix
8+
* Use of this source code is governed by a MIT license
9+
* that can be found in the License file.
10+
*
11+
* Vix.cpp
12+
*
13+
* Dev mode project rebuilder
14+
*
15+
*/
16+
17+
#ifndef VIX_CLI_COMMANDS_RUN_DEV_DEV_REBUILDER_HPP
18+
#define VIX_CLI_COMMANDS_RUN_DEV_DEV_REBUILDER_HPP
19+
20+
#include <filesystem>
21+
#include <string>
22+
23+
#include <vix/cli/commands/run/RunDetail.hpp>
24+
25+
namespace vix::commands::RunCommand::dev
26+
{
27+
namespace fs = std::filesystem;
28+
namespace detail = vix::commands::RunCommand::detail;
29+
30+
struct DevRebuilderOptions
31+
{
32+
fs::path projectDir;
33+
fs::path buildDir;
34+
std::string targetName;
35+
36+
detail::Options runOptions;
37+
38+
bool quiet{false};
39+
};
40+
41+
struct DevRebuilderResult
42+
{
43+
bool ok{false};
44+
bool configured{false};
45+
bool built{false};
46+
47+
int exitCode{0};
48+
std::string message;
49+
std::string output;
50+
};
51+
52+
class DevRebuilder
53+
{
54+
public:
55+
explicit DevRebuilder(DevRebuilderOptions options);
56+
57+
const DevRebuilderOptions &options() const;
58+
59+
DevRebuilderResult ensure_configured() const;
60+
DevRebuilderResult rebuild() const;
61+
DevRebuilderResult reconfigure_and_rebuild() const;
62+
63+
private:
64+
DevRebuilderOptions options_;
65+
66+
bool has_cmake_cache() const;
67+
68+
std::string configure_command() const;
69+
std::string build_command() const;
70+
71+
DevRebuilderResult run_configure_command() const;
72+
DevRebuilderResult run_build_command() const;
73+
};
74+
75+
} // namespace vix::commands::RunCommand::dev
76+
77+
#endif // VIX_CLI_COMMANDS_RUN_DEV_DEV_REBUILDER_HPP
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/**
2+
*
3+
* @file DevSession.hpp
4+
* @author Gaspard Kirira
5+
*
6+
* Copyright 2026, Gaspard Kirira. All rights reserved.
7+
* https://github.com/vixcpp/vix
8+
* Use of this source code is governed by a MIT license
9+
* that can be found in the License file.
10+
*
11+
* Vix.cpp
12+
*
13+
* Dev mode session orchestrator
14+
*
15+
*/
16+
17+
#ifndef VIX_CLI_COMMANDS_RUN_DEV_DEV_SESSION_HPP
18+
#define VIX_CLI_COMMANDS_RUN_DEV_DEV_SESSION_HPP
19+
20+
#include <chrono>
21+
#include <filesystem>
22+
#include <map>
23+
#include <string>
24+
#include <vector>
25+
26+
#include <vix/cli/commands/run/RunDetail.hpp>
27+
#include <vix/cli/commands/run/dev/DevChangeClassifier.hpp>
28+
#include <vix/cli/commands/run/dev/DevRebuilder.hpp>
29+
30+
namespace vix::commands::RunCommand::dev
31+
{
32+
namespace fs = std::filesystem;
33+
namespace detail = vix::commands::RunCommand::detail;
34+
35+
struct DevSessionOptions
36+
{
37+
fs::path projectDir;
38+
fs::path buildDir;
39+
std::string targetName;
40+
41+
detail::Options runOptions;
42+
43+
std::chrono::milliseconds pollInterval{300};
44+
std::chrono::milliseconds debounceDelay{200};
45+
46+
bool quiet{false};
47+
};
48+
49+
struct DevSessionResult
50+
{
51+
int exitCode{0};
52+
std::string message;
53+
};
54+
55+
struct DevFileSnapshot
56+
{
57+
std::map<std::string, fs::file_time_type> files;
58+
59+
bool empty() const;
60+
};
61+
62+
struct DevDetectedChange
63+
{
64+
fs::path path;
65+
DevChangeKind kind{DevChangeKind::Ignore};
66+
67+
bool valid() const;
68+
};
69+
70+
class DevSession
71+
{
72+
public:
73+
explicit DevSession(DevSessionOptions options);
74+
75+
const DevSessionOptions &options() const;
76+
77+
DevSessionResult run();
78+
79+
private:
80+
DevSessionOptions options_;
81+
DevChangeClassifier classifier_;
82+
DevRebuilder rebuilder_;
83+
84+
DevFileSnapshot snapshot_project() const;
85+
86+
std::vector<DevDetectedChange> detect_changes(
87+
const DevFileSnapshot &before,
88+
const DevFileSnapshot &after) const;
89+
90+
DevChangeKind strongest_change_kind(
91+
const std::vector<DevDetectedChange> &changes) const;
92+
93+
DevDetectedChange first_relevant_change(
94+
const std::vector<DevDetectedChange> &changes) const;
95+
96+
DevDetectedChange wait_for_change(
97+
DevFileSnapshot &snapshot) const;
98+
99+
int rebuild_for_change(DevChangeKind kind) const;
100+
101+
fs::path executable_path() const;
102+
103+
#ifndef _WIN32
104+
int run_child_once(const fs::path &exePath);
105+
void stop_child(int pid) const;
106+
#endif
107+
108+
bool should_skip_directory(const fs::path &path) const;
109+
};
110+
111+
} // namespace vix::commands::RunCommand::dev
112+
113+
#endif // VIX_CLI_COMMANDS_RUN_DEV_DEV_SESSION_HPP

src/commands/run/RunScript.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <vix/cli/errors/RawLogDetectors.hpp>
2323
#include <vix/cli/Style.hpp>
2424
#include <vix/utils/Env.hpp>
25+
#include <vix/cli/commands/run/dev/DevSession.hpp>
2526

2627
#include <algorithm>
2728
#include <cerrno>
@@ -1575,6 +1576,22 @@ namespace vix::commands::RunCommand::detail
15751576
const fs::path buildDir = projectDir / (devMode ? "build-ninja" : "build-dev");
15761577
const std::string targetName = projectDir.filename().string();
15771578

1579+
if (devMode)
1580+
{
1581+
vix::commands::RunCommand::dev::DevSession session(
1582+
vix::commands::RunCommand::dev::DevSessionOptions{
1583+
projectDir,
1584+
buildDir,
1585+
targetName,
1586+
opt,
1587+
std::chrono::milliseconds(300),
1588+
std::chrono::milliseconds(200),
1589+
opt.quiet});
1590+
1591+
const auto result = session.run();
1592+
return result.exitCode;
1593+
}
1594+
15781595
if (devMode)
15791596
{
15801597
info("Vix dev mode enabled.");

0 commit comments

Comments
 (0)