| 1 | import os |
| 2 | |
| 3 | const vexe = @VEXE |
| 4 | const git_exe = os.find_abs_path_of_executable('git') or { '' } |
| 5 | |
| 6 | fn test_check_md_respects_vcheckignore() { |
| 7 | if git_exe == '' { |
| 8 | eprintln('git is required for this test; skipping') |
| 9 | return |
| 10 | } |
| 11 | original_wd := os.getwd() |
| 12 | mut repo_dir := os.join_path(os.vtmp_dir(), 'vcheckignore_test_${os.getpid()}') |
| 13 | os.rmdir_all(repo_dir) or {} |
| 14 | os.mkdir_all(repo_dir)! |
| 15 | defer { |
| 16 | os.chdir(original_wd) or {} |
| 17 | os.rmdir_all(repo_dir) or {} |
| 18 | } |
| 19 | os.execute_or_exit('${os.quoted_path(git_exe)} init ${os.quoted_path(repo_dir)}') |
| 20 | |
| 21 | write_text_file(os.join_path(repo_dir, 'README.md'), '# Root\n')! |
| 22 | write_text_file(os.join_path(repo_dir, 'docs', 'cwd_skip.md'), '# CWD skip\n')! |
| 23 | write_text_file(os.join_path(repo_dir, 'docs', 'skip.md'), '# Skip me\n')! |
| 24 | write_text_file(os.join_path(repo_dir, 'docs', 'sub', 'skip2.md'), '# Skip me too\n')! |
| 25 | write_text_file(os.join_path(repo_dir, 'notes', 'keep2.md'), '# Keep 2\n')! |
| 26 | |
| 27 | write_text_file(os.join_path(repo_dir, '.vcheckignore'), 'docs/skip.md\ndocs/sub/*.md\n')! |
| 28 | write_text_file(os.join_path(repo_dir, 'docs', '.vcheckignore'), 'cwd_skip.md\n')! |
| 29 | |
| 30 | check_cmd := '${os.quoted_path(vexe)} check-md -hide-warnings -silent .' |
| 31 | |
| 32 | root_res := run_in_dir(repo_dir, check_cmd, true)! |
| 33 | assert root_res.exit_code == 0, root_res.output |
| 34 | assert root_res.output.contains('SKIP: docs/cwd_skip.md'), root_res.output |
| 35 | assert root_res.output.contains('SKIP: docs/skip.md'), root_res.output |
| 36 | assert root_res.output.contains('SKIP: docs/sub/skip2.md'), root_res.output |
| 37 | assert root_res.output.contains('from docs/.vcheckignore: cwd_skip.md'), root_res.output |
| 38 | assert root_res.output.contains('from .vcheckignore: docs/skip.md'), root_res.output |
| 39 | assert root_res.output.contains('from .vcheckignore: docs/sub/*.md'), root_res.output |
| 40 | assert root_res.output.contains('> Found: 2 .md files.'), root_res.output |
| 41 | assert root_res.output.contains('Skipped by .vcheckignore: 3.'), root_res.output |
| 42 | assert root_res.output.contains('Checked .md files: 2 |'), root_res.output |
| 43 | root_non_verbose_res := run_in_dir(repo_dir, check_cmd, false)! |
| 44 | assert root_non_verbose_res.exit_code == 0, root_non_verbose_res.output |
| 45 | assert !root_non_verbose_res.output.contains('SKIP:'), root_non_verbose_res.output |
| 46 | |
| 47 | docs_res := run_in_dir(os.join_path(repo_dir, 'docs'), check_cmd, true)! |
| 48 | assert docs_res.exit_code == 0, docs_res.output |
| 49 | assert docs_res.output.contains('SKIP: docs/cwd_skip.md'), docs_res.output |
| 50 | assert docs_res.output.contains('SKIP: docs/skip.md'), docs_res.output |
| 51 | assert docs_res.output.contains('SKIP: docs/sub/skip2.md'), docs_res.output |
| 52 | assert docs_res.output.contains('from docs/.vcheckignore: cwd_skip.md'), docs_res.output |
| 53 | assert docs_res.output.contains('> Found: 0 .md files.'), docs_res.output |
| 54 | assert docs_res.output.contains('Skipped by .vcheckignore: 3.'), docs_res.output |
| 55 | assert docs_res.output.contains('Checked .md files: 0 |'), docs_res.output |
| 56 | |
| 57 | sub_res := run_in_dir(os.join_path(repo_dir, 'docs', 'sub'), check_cmd, true)! |
| 58 | assert sub_res.exit_code == 0, sub_res.output |
| 59 | assert sub_res.output.contains('SKIP: docs/sub/skip2.md'), sub_res.output |
| 60 | assert !sub_res.output.contains('SKIP: docs/cwd_skip.md'), sub_res.output |
| 61 | assert sub_res.output.contains('from .vcheckignore: docs/sub/*.md'), sub_res.output |
| 62 | assert sub_res.output.contains('> Found: 0 .md files.'), sub_res.output |
| 63 | assert sub_res.output.contains('Skipped by .vcheckignore: 1.'), sub_res.output |
| 64 | assert sub_res.output.contains('Checked .md files: 0 |'), sub_res.output |
| 65 | } |
| 66 | |
| 67 | fn test_check_md_respects_vcheckignore_glob_in_scanned_dir() { |
| 68 | if git_exe == '' { |
| 69 | eprintln('git is required for this test; skipping') |
| 70 | return |
| 71 | } |
| 72 | original_wd := os.getwd() |
| 73 | repo_dir := os.join_path(os.vtmp_dir(), 'vcheckignore_glob_${os.getpid()}') |
| 74 | os.rmdir_all(repo_dir) or {} |
| 75 | os.mkdir_all(repo_dir)! |
| 76 | defer { |
| 77 | os.chdir(original_wd) or {} |
| 78 | os.rmdir_all(repo_dir) or {} |
| 79 | } |
| 80 | os.execute_or_exit('${os.quoted_path(git_exe)} init ${os.quoted_path(repo_dir)}') |
| 81 | |
| 82 | write_text_file(os.join_path(repo_dir, 'doc', 'plans', 'ignored1.md'), '# ignored\n')! |
| 83 | write_text_file(os.join_path(repo_dir, 'doc', 'plans', 'ignored2.md'), '# ignored\n')! |
| 84 | write_text_file(os.join_path(repo_dir, 'doc', 'plans', 'ignored3.md'), '# ignored\n')! |
| 85 | write_text_file(os.join_path(repo_dir, 'doc', 'plans', 'keep1.md'), '# keep\n')! |
| 86 | write_text_file(os.join_path(repo_dir, 'doc', 'plans', 'keep2.md'), '# keep\n')! |
| 87 | write_text_file(os.join_path(repo_dir, 'doc', 'plans', 'keep3.md'), '# keep\n')! |
| 88 | write_text_file(os.join_path(repo_dir, 'doc', 'plans', '.vcheckignore'), 'ignored*.md\n')! |
| 89 | |
| 90 | res := run_in_dir(repo_dir, |
| 91 | '${os.quoted_path(vexe)} check-md -hide-warnings -silent doc/plans', true)! |
| 92 | assert res.exit_code == 0, res.output |
| 93 | assert res.output.contains('SKIP: doc/plans/ignored1.md'), res.output |
| 94 | assert res.output.contains('SKIP: doc/plans/ignored2.md'), res.output |
| 95 | assert res.output.contains('SKIP: doc/plans/ignored3.md'), res.output |
| 96 | assert res.output.contains('from doc/plans/.vcheckignore: ignored*.md'), res.output |
| 97 | assert res.output.contains('> Found: 3 .md files.'), res.output |
| 98 | assert res.output.contains('Skipped by .vcheckignore: 3.'), res.output |
| 99 | assert res.output.contains('Checked .md files: 3 |'), res.output |
| 100 | } |
| 101 | |
| 102 | fn test_check_md_respects_vcheckignore_anchored_pattern() { |
| 103 | if git_exe == '' { |
| 104 | eprintln('git is required for this test; skipping') |
| 105 | return |
| 106 | } |
| 107 | original_wd := os.getwd() |
| 108 | repo_dir := os.join_path(os.vtmp_dir(), 'vcheckignore_anchored_${os.getpid()}') |
| 109 | os.rmdir_all(repo_dir) or {} |
| 110 | os.mkdir_all(repo_dir)! |
| 111 | defer { |
| 112 | os.chdir(original_wd) or {} |
| 113 | os.rmdir_all(repo_dir) or {} |
| 114 | } |
| 115 | os.execute_or_exit('${os.quoted_path(git_exe)} init ${os.quoted_path(repo_dir)}') |
| 116 | |
| 117 | write_text_file(os.join_path(repo_dir, 'docs', 'root_only.md'), '# ignored by /root_only.md\n')! |
| 118 | write_text_file(os.join_path(repo_dir, 'docs', 'sub', 'root_only.md'), '# should be kept\n')! |
| 119 | write_text_file(os.join_path(repo_dir, 'docs', 'keep.md'), '# keep\n')! |
| 120 | write_text_file(os.join_path(repo_dir, 'docs', '.vcheckignore'), '/root_only.md\n')! |
| 121 | |
| 122 | res := |
| 123 | run_in_dir(repo_dir, '${os.quoted_path(vexe)} check-md -hide-warnings -silent docs', true)! |
| 124 | assert res.exit_code == 0, res.output |
| 125 | assert res.output.contains('SKIP: docs/root_only.md'), res.output |
| 126 | assert res.output.contains('from docs/.vcheckignore: /root_only.md'), res.output |
| 127 | assert !res.output.contains('SKIP: docs/sub/root_only.md'), res.output |
| 128 | assert res.output.contains('> Found: 2 .md files.'), res.output |
| 129 | assert res.output.contains('Skipped by .vcheckignore: 1.'), res.output |
| 130 | assert res.output.contains('Checked .md files: 2 |'), res.output |
| 131 | } |
| 132 | |
| 133 | fn test_check_md_respects_vcheckignore_anchored_directory_pattern() { |
| 134 | if git_exe == '' { |
| 135 | eprintln('git is required for this test; skipping') |
| 136 | return |
| 137 | } |
| 138 | original_wd := os.getwd() |
| 139 | repo_dir := os.join_path(os.vtmp_dir(), 'vcheckignore_anchored_dir_${os.getpid()}') |
| 140 | os.rmdir_all(repo_dir) or {} |
| 141 | os.mkdir_all(repo_dir)! |
| 142 | defer { |
| 143 | os.chdir(original_wd) or {} |
| 144 | os.rmdir_all(repo_dir) or {} |
| 145 | } |
| 146 | os.execute_or_exit('${os.quoted_path(git_exe)} init ${os.quoted_path(repo_dir)}') |
| 147 | |
| 148 | write_text_file(os.join_path(repo_dir, 'docs', 'sub', 'ignored.md'), '# ignored by /sub/\n')! |
| 149 | write_text_file(os.join_path(repo_dir, 'docs', 'nested', 'sub', 'keep.md'), '# kept\n')! |
| 150 | write_text_file(os.join_path(repo_dir, 'docs', 'keep.md'), '# keep\n')! |
| 151 | write_text_file(os.join_path(repo_dir, 'docs', '.vcheckignore'), '/sub/\n')! |
| 152 | |
| 153 | res := |
| 154 | run_in_dir(repo_dir, '${os.quoted_path(vexe)} check-md -hide-warnings -silent docs', true)! |
| 155 | assert res.exit_code == 0, res.output |
| 156 | assert res.output.contains('SKIP: docs/sub/ignored.md'), res.output |
| 157 | assert res.output.contains('from docs/.vcheckignore: /sub/'), res.output |
| 158 | assert !res.output.contains('SKIP: docs/nested/sub/keep.md'), res.output |
| 159 | assert res.output.contains('> Found: 2 .md files.'), res.output |
| 160 | assert res.output.contains('Skipped by .vcheckignore: 1.'), res.output |
| 161 | assert res.output.contains('Checked .md files: 2 |'), res.output |
| 162 | } |
| 163 | |
| 164 | fn test_check_md_respects_vcheckignore_non_anchored_directory_pattern() { |
| 165 | if git_exe == '' { |
| 166 | eprintln('git is required for this test; skipping') |
| 167 | return |
| 168 | } |
| 169 | original_wd := os.getwd() |
| 170 | repo_dir := os.join_path(os.vtmp_dir(), 'vcheckignore_non_anchored_dir_${os.getpid()}') |
| 171 | os.rmdir_all(repo_dir) or {} |
| 172 | os.mkdir_all(repo_dir)! |
| 173 | defer { |
| 174 | os.chdir(original_wd) or {} |
| 175 | os.rmdir_all(repo_dir) or {} |
| 176 | } |
| 177 | os.execute_or_exit('${os.quoted_path(git_exe)} init ${os.quoted_path(repo_dir)}') |
| 178 | |
| 179 | write_text_file(os.join_path(repo_dir, 'docs', 'sub', 'ignored1.md'), '# ignored 1\n')! |
| 180 | write_text_file(os.join_path(repo_dir, 'docs', 'nested', 'sub', 'ignored2.md'), '# ignored 2\n')! |
| 181 | write_text_file(os.join_path(repo_dir, 'docs', 'keep.md'), '# keep\n')! |
| 182 | write_text_file(os.join_path(repo_dir, 'docs', '.vcheckignore'), 'sub/\n')! |
| 183 | |
| 184 | res := |
| 185 | run_in_dir(repo_dir, '${os.quoted_path(vexe)} check-md -hide-warnings -silent docs', true)! |
| 186 | assert res.exit_code == 0, res.output |
| 187 | assert res.output.contains('SKIP: docs/sub/ignored1.md'), res.output |
| 188 | assert res.output.contains('SKIP: docs/nested/sub/ignored2.md'), res.output |
| 189 | assert res.output.contains('from docs/.vcheckignore: sub/'), res.output |
| 190 | assert res.output.contains('> Found: 1 .md files.'), res.output |
| 191 | assert res.output.contains('Skipped by .vcheckignore: 2.'), res.output |
| 192 | assert res.output.contains('Checked .md files: 1 |'), res.output |
| 193 | } |
| 194 | |
| 195 | fn test_check_md_respects_vcheckignore_anchored_directory_glob_pattern() { |
| 196 | if git_exe == '' { |
| 197 | eprintln('git is required for this test; skipping') |
| 198 | return |
| 199 | } |
| 200 | original_wd := os.getwd() |
| 201 | repo_dir := os.join_path(os.vtmp_dir(), 'vcheckignore_anchored_dir_glob_${os.getpid()}') |
| 202 | os.rmdir_all(repo_dir) or {} |
| 203 | os.mkdir_all(repo_dir)! |
| 204 | defer { |
| 205 | os.chdir(original_wd) or {} |
| 206 | os.rmdir_all(repo_dir) or {} |
| 207 | } |
| 208 | os.execute_or_exit('${os.quoted_path(git_exe)} init ${os.quoted_path(repo_dir)}') |
| 209 | |
| 210 | write_text_file(os.join_path(repo_dir, 'docs-a', 'sub', 'ignored1.md'), '# ignored 1\n')! |
| 211 | write_text_file(os.join_path(repo_dir, 'docs-b', 'sub', 'ignored2.md'), '# ignored 2\n')! |
| 212 | write_text_file(os.join_path(repo_dir, 'other', 'keep.md'), '# keep\n')! |
| 213 | write_text_file(os.join_path(repo_dir, '.vcheckignore'), '/docs-*/\n')! |
| 214 | |
| 215 | res := run_in_dir(repo_dir, '${os.quoted_path(vexe)} check-md -hide-warnings -silent .', true)! |
| 216 | assert res.exit_code == 0, res.output |
| 217 | assert res.output.contains('SKIP: docs-a/sub/ignored1.md'), res.output |
| 218 | assert res.output.contains('SKIP: docs-b/sub/ignored2.md'), res.output |
| 219 | assert res.output.contains('from .vcheckignore: /docs-*/'), res.output |
| 220 | assert !res.output.contains('SKIP: other/keep.md'), res.output |
| 221 | assert res.output.contains('> Found: 1 .md files.'), res.output |
| 222 | assert res.output.contains('Skipped by .vcheckignore: 2.'), res.output |
| 223 | assert res.output.contains('Checked .md files: 1 |'), res.output |
| 224 | } |
| 225 | |
| 226 | fn test_check_md_respects_vcheckignore_comments_and_blank_lines() { |
| 227 | if git_exe == '' { |
| 228 | eprintln('git is required for this test; skipping') |
| 229 | return |
| 230 | } |
| 231 | original_wd := os.getwd() |
| 232 | repo_dir := os.join_path(os.vtmp_dir(), 'vcheckignore_comments_${os.getpid()}') |
| 233 | os.rmdir_all(repo_dir) or {} |
| 234 | os.mkdir_all(repo_dir)! |
| 235 | defer { |
| 236 | os.chdir(original_wd) or {} |
| 237 | os.rmdir_all(repo_dir) or {} |
| 238 | } |
| 239 | os.execute_or_exit('${os.quoted_path(git_exe)} init ${os.quoted_path(repo_dir)}') |
| 240 | |
| 241 | write_text_file(os.join_path(repo_dir, 'docs', 'ignored.md'), '# ignored\n')! |
| 242 | write_text_file(os.join_path(repo_dir, 'docs', 'ignored2.md'), '# ignored2\n')! |
| 243 | write_text_file(os.join_path(repo_dir, 'docs', 'keep.md'), '# keep\n')! |
| 244 | write_text_file(os.join_path(repo_dir, 'docs', '.vcheckignore'), |
| 245 | '# comment\n\nignored.md # inline comment\nignored2.md\n')! |
| 246 | |
| 247 | res := |
| 248 | run_in_dir(repo_dir, '${os.quoted_path(vexe)} check-md -hide-warnings -silent docs', true)! |
| 249 | assert res.exit_code == 0, res.output |
| 250 | assert res.output.contains('SKIP: docs/ignored.md'), res.output |
| 251 | assert res.output.contains('SKIP: docs/ignored2.md'), res.output |
| 252 | assert res.output.contains('from docs/.vcheckignore: ignored.md'), res.output |
| 253 | assert res.output.contains('from docs/.vcheckignore: ignored2.md'), res.output |
| 254 | assert !res.output.contains('SKIP: docs/keep.md'), res.output |
| 255 | assert res.output.contains('> Found: 1 .md files.'), res.output |
| 256 | assert res.output.contains('Skipped by .vcheckignore: 2.'), res.output |
| 257 | assert res.output.contains('Checked .md files: 1 |'), res.output |
| 258 | } |
| 259 | |
| 260 | fn test_check_md_file_argument_does_not_use_vcheckignore_directory_filtering() { |
| 261 | if git_exe == '' { |
| 262 | eprintln('git is required for this test; skipping') |
| 263 | return |
| 264 | } |
| 265 | original_wd := os.getwd() |
| 266 | repo_dir := os.join_path(os.vtmp_dir(), 'vcheckignore_file_argument_${os.getpid()}') |
| 267 | os.rmdir_all(repo_dir) or {} |
| 268 | os.mkdir_all(repo_dir)! |
| 269 | defer { |
| 270 | os.chdir(original_wd) or {} |
| 271 | os.rmdir_all(repo_dir) or {} |
| 272 | } |
| 273 | os.execute_or_exit('${os.quoted_path(git_exe)} init ${os.quoted_path(repo_dir)}') |
| 274 | |
| 275 | write_text_file(os.join_path(repo_dir, 'docs', 'ignored.md'), '# ignored by dir scan\n')! |
| 276 | write_text_file(os.join_path(repo_dir, 'docs', '.vcheckignore'), 'ignored.md\n')! |
| 277 | |
| 278 | res := run_in_dir(repo_dir, |
| 279 | '${os.quoted_path(vexe)} check-md -hide-warnings -silent docs/ignored.md', true)! |
| 280 | assert res.exit_code == 0, res.output |
| 281 | assert !res.output.contains('SKIP: docs/ignored.md'), res.output |
| 282 | assert res.output.contains('> Found: 1 .md files.'), res.output |
| 283 | assert res.output.contains('Skipped by .vcheckignore: 0.'), res.output |
| 284 | assert res.output.contains('Checked .md files: 1 |'), res.output |
| 285 | } |
| 286 | |
| 287 | fn test_check_md_uses_scanned_dir_repo_root_for_vcheckignore() { |
| 288 | if git_exe == '' { |
| 289 | eprintln('git is required for this test; skipping') |
| 290 | return |
| 291 | } |
| 292 | original_wd := os.getwd() |
| 293 | base_dir := os.join_path(os.vtmp_dir(), 'vcheckignore_repo_root_${os.getpid()}') |
| 294 | repo_a := os.join_path(base_dir, 'repo_a') |
| 295 | repo_b := os.join_path(base_dir, 'repo_b') |
| 296 | os.rmdir_all(base_dir) or {} |
| 297 | os.mkdir_all(os.join_path(repo_b, 'docs'))! |
| 298 | defer { |
| 299 | os.chdir(original_wd) or {} |
| 300 | os.rmdir_all(base_dir) or {} |
| 301 | } |
| 302 | os.execute_or_exit('${os.quoted_path(git_exe)} init ${os.quoted_path(repo_a)}') |
| 303 | os.execute_or_exit('${os.quoted_path(git_exe)} init ${os.quoted_path(repo_b)}') |
| 304 | |
| 305 | write_text_file(os.join_path(base_dir, '.vcheckignore'), 'outside*.md\n')! |
| 306 | write_text_file(os.join_path(repo_b, 'docs', 'outside1.md'), |
| 307 | '# outside but should not be skipped\n')! |
| 308 | write_text_file(os.join_path(repo_b, 'docs', 'keep1.md'), '# keep\n')! |
| 309 | |
| 310 | res := run_in_dir(repo_a, '${os.quoted_path(vexe)} check-md -hide-warnings -silent ${os.quoted_path(os.join_path(repo_b, |
| 311 | 'docs'))}', true)! |
| 312 | assert res.exit_code == 0, res.output |
| 313 | assert !res.output.contains('SKIP: '), res.output |
| 314 | assert res.output.contains('> Found: 2 .md files.'), res.output |
| 315 | assert res.output.contains('Skipped by .vcheckignore: 0.'), res.output |
| 316 | assert res.output.contains('Checked .md files: 2 |'), res.output |
| 317 | } |
| 318 | |
| 319 | fn test_check_md_multiple_directories_accumulate_skipped_count() { |
| 320 | if git_exe == '' { |
| 321 | eprintln('git is required for this test; skipping') |
| 322 | return |
| 323 | } |
| 324 | original_wd := os.getwd() |
| 325 | repo_dir := os.join_path(os.vtmp_dir(), 'vcheckignore_multi_dirs_${os.getpid()}') |
| 326 | os.rmdir_all(repo_dir) or {} |
| 327 | os.mkdir_all(repo_dir)! |
| 328 | defer { |
| 329 | os.chdir(original_wd) or {} |
| 330 | os.rmdir_all(repo_dir) or {} |
| 331 | } |
| 332 | os.execute_or_exit('${os.quoted_path(git_exe)} init ${os.quoted_path(repo_dir)}') |
| 333 | |
| 334 | write_text_file(os.join_path(repo_dir, 'docs', 'ignored.md'), '# ignored\n')! |
| 335 | write_text_file(os.join_path(repo_dir, 'docs', 'keep.md'), '# keep\n')! |
| 336 | write_text_file(os.join_path(repo_dir, 'notes', 'ignored.md'), '# ignored\n')! |
| 337 | write_text_file(os.join_path(repo_dir, 'notes', 'keep.md'), '# keep\n')! |
| 338 | write_text_file(os.join_path(repo_dir, '.vcheckignore'), 'docs/ignored.md\nnotes/ignored.md\n')! |
| 339 | |
| 340 | res := run_in_dir(repo_dir, |
| 341 | '${os.quoted_path(vexe)} check-md -hide-warnings -silent docs notes', true)! |
| 342 | assert res.exit_code == 0, res.output |
| 343 | assert res.output.contains('SKIP: docs/ignored.md'), res.output |
| 344 | assert res.output.contains('SKIP: notes/ignored.md'), res.output |
| 345 | assert res.output.contains('> Found: 2 .md files.'), res.output |
| 346 | assert res.output.contains('Skipped by .vcheckignore: 2.'), res.output |
| 347 | assert res.output.contains('Checked .md files: 2 |'), res.output |
| 348 | } |
| 349 | |
| 350 | fn run_in_dir(path string, cmd string, verbose bool) !os.Result { |
| 351 | original_wd := os.getwd() |
| 352 | os.chdir(path)! |
| 353 | if verbose { |
| 354 | os.setenv('VERBOSE', '1', true) |
| 355 | } else { |
| 356 | os.unsetenv('VERBOSE') |
| 357 | } |
| 358 | res := os.execute(cmd) |
| 359 | os.unsetenv('VERBOSE') |
| 360 | os.chdir(original_wd)! |
| 361 | return res |
| 362 | } |
| 363 | |
| 364 | fn write_text_file(path string, content string) ! { |
| 365 | os.mkdir_all(os.dir(path))! |
| 366 | os.write_file(path, content)! |
| 367 | } |
| 368 | |