Skip to content

Commit 257e14c

Browse files
authored
Merge pull request #93 from build-cpp/gitattributes
Automatically generate .gitattributes and .gitignore with cmkr init
2 parents 7508816 + 45678bc commit 257e14c

File tree

1 file changed

+76
-1
lines changed

1 file changed

+76
-1
lines changed

src/cmake_generator.cpp

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,19 @@ static void create_file(const fs::path &path, const std::string &contents) {
119119
ofs << contents;
120120
}
121121

122+
static std::string read_file(const fs::path &path) {
123+
std::ifstream ifs(path, std::ios::binary);
124+
if (!ifs) {
125+
throw std::runtime_error("Failed to read " + path.string());
126+
}
127+
std::string contents;
128+
ifs.seekg(0, std::ios::end);
129+
contents.resize(ifs.tellg());
130+
ifs.seekg(0, std::ios::beg);
131+
ifs.read(&contents[0], contents.size());
132+
return contents;
133+
}
134+
122135
// CMake target name rules: https://cmake.org/cmake/help/latest/policy/CMP0037.html [A-Za-z0-9_.+\-]
123136
// TOML bare keys: non-empty strings composed only of [A-Za-z0-9_-]
124137
// We replace all non-TOML bare key characters with _
@@ -135,12 +148,74 @@ static std::string escape_project_name(const std::string &name) {
135148
return escaped;
136149
}
137150

151+
static void generate_gitfile(const char *gitfile, const std::vector<std::string> &desired_lines) {
152+
// Reference: https://github.com/github/linguist/blob/master/docs/overrides.md#summary
153+
auto lines = desired_lines;
154+
auto generate = [&lines](const char *newline) {
155+
std::string generated;
156+
generated += "# cmkr";
157+
generated += newline;
158+
for (const auto &line : lines) {
159+
generated += line;
160+
generated += newline;
161+
}
162+
return generated;
163+
};
164+
if (!fs::exists(gitfile)) {
165+
create_file(gitfile, generate("\n"));
166+
} else {
167+
auto contents = read_file(gitfile);
168+
std::string line;
169+
auto cr = 0, lf = 0;
170+
auto flush_line = [&line, &lines]() {
171+
auto itr = std::find(lines.begin(), lines.end(), line);
172+
if (itr != lines.end()) {
173+
printf("erase:%s\n", line.c_str());
174+
lines.erase(itr);
175+
}
176+
line.clear();
177+
};
178+
for (size_t i = 0; i < contents.length(); i++) {
179+
if (contents[i] == '\r') {
180+
cr++;
181+
continue;
182+
}
183+
if (contents[i] == '\n') {
184+
lf++;
185+
flush_line();
186+
} else {
187+
line += contents[i];
188+
}
189+
}
190+
if (!line.empty()) {
191+
flush_line();
192+
}
193+
194+
if (!lines.empty()) {
195+
// Append the cmkr .gitattributes using the detected newline
196+
auto newline = cr == lf ? "\r\n" : "\n";
197+
if (!contents.empty() && contents.back() != '\n') {
198+
contents += newline;
199+
}
200+
contents += newline;
201+
contents += generate(newline);
202+
create_file(gitfile, contents);
203+
}
204+
}
205+
}
206+
138207
void generate_project(const std::string &type) {
139208
const auto name = escape_project_name(fs::current_path().stem().string());
140209
if (fs::exists(fs::current_path() / "cmake.toml")) {
141210
throw std::runtime_error("Cannot initialize a project when cmake.toml already exists!");
142211
}
143212

213+
// Automatically generate .gitattributes to not skew the statistics of the repo
214+
generate_gitfile(".gitattributes", {"/**/CMakeLists.txt linguist-generated", "/**/cmkr.cmake linguist-vendored"});
215+
216+
// Generate .gitignore with reasonable defaults for CMake
217+
generate_gitfile(".gitignore", {"build*/", "cmake-build*/", ".idea/", ".vscode/"});
218+
144219
tsl::ordered_map<std::string, std::string> variables = {
145220
{"@name", name},
146221
{"@type", type},
@@ -898,7 +973,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
898973
}
899974
}
900975

901-
auto contains_language_source = [&project_extensions](const std::vector<std::string>& sources) {
976+
auto contains_language_source = [&project_extensions](const std::vector<std::string> &sources) {
902977
for (const auto &source : sources) {
903978
auto extension = fs::path(source).extension().string();
904979
if (project_extensions.count(extension) > 0) {

0 commit comments

Comments
 (0)