]> Kevux Git Server - fll/commitdiff
Progress: featureless make.
authorKevin Day <thekevinday@gmail.com>
Wed, 19 Aug 2020 03:09:20 +0000 (22:09 -0500)
committerKevin Day <thekevinday@gmail.com>
Wed, 19 Aug 2020 03:10:53 +0000 (22:10 -0500)
Implement the compiler and linker section operations.

Rename and move the fake_build_execute() to fake_execute() to be shared among both the build and the make operations.

level_3/fake/c/private-build.c
level_3/fake/c/private-build.h
level_3/fake/c/private-fake.c
level_3/fake/c/private-fake.h
level_3/fake/c/private-make.c
level_3/fake/c/private-make.h
level_3/fake/data/build/fakefile
level_3/fake/documents/fakefile.txt
level_3/fake/specifications/fakefile.txt

index e5c90a83ce2e94d33c7eb0df30ca8562f18ab1f6..d8e3cca1d4f8a8cd68f57810ac3e621ca4c25b29 100644 (file)
@@ -295,50 +295,6 @@ extern "C" {
   }
 #endif // _di_fake_build_copy_
 
-#ifndef _di_fake_build_execute_
-  void fake_build_execute(const fake_data data, const fake_build_data data_build, const f_string_static program, const f_string_statics arguments, f_status *status) {
-    if (F_status_is_error(*status)) return;
-
-    if (data.verbosity == fake_verbosity_verbose) {
-      printf("%s", program.string);
-
-      for (f_array_length i = 0; i < arguments.used; i++) {
-        if (arguments.array[i].used == 0) continue;
-
-        printf(" %s", arguments.array[i].string);
-      } // for
-
-      printf("%c", f_string_eol[0]);
-
-      // flush to stdout before executing command.
-      fflush(f_type_output);
-    }
-
-    {
-      int result = 0;
-
-      *status = fll_execute_program_environment(program.string, arguments, data_build.environment.names, data_build.environment.values, &result);
-
-      if (result != 0) {
-        *status = F_status_set_error(F_failure);
-      }
-      else if (F_status_is_error(*status)) {
-        if (F_status_set_fine(*status) == F_file_found_not) {
-          if (data.verbosity != fake_verbosity_quiet) {
-            fprintf(f_type_error, "%c", f_string_eol[0]);
-            fl_color_print(f_type_error, data.context.error, data.context.reset, "ERROR: Failed to find program '");
-            fl_color_print(f_type_error, data.context.notable, data.context.reset, "%s", program.string);
-            fl_color_print_line(f_type_error, data.context.error, data.context.reset, "' for executing.");
-          }
-        }
-        else {
-          fake_print_error(data, F_status_set_fine(*status), "fll_execute_program_environment", F_true);
-        }
-      }
-    }
-  }
-#endif // _di_fake_build_execute_
-
 #ifndef _di_fake_build_skeleton_
   void fake_build_skeleton(const fake_data data, const fake_build_data data_build, const mode_t mode, const f_string_static file_stage, f_status *status) {
     if (F_status_is_error(*status) || f_file_exists(file_stage.string) == F_true) return;
@@ -844,7 +800,7 @@ extern "C" {
       }
     }
 
-    fake_build_execute(data, data_build, data_build.setting.build_compiler, arguments, status);
+    fake_execute(data, data_build.environment, data_build.setting.build_compiler, arguments, status);
 
     f_macro_string_dynamics_delete_simple(arguments);
 
@@ -1067,7 +1023,7 @@ extern "C" {
       }
     }
 
-    fake_build_execute(data, data_build, data_build.setting.build_linker, arguments, status);
+    fake_execute(data, data_build.environment, data_build.setting.build_linker, arguments, status);
 
     f_macro_string_dynamic_delete_simple(file_name);
     f_macro_string_dynamic_delete_simple(source_path);
@@ -2263,7 +2219,7 @@ extern "C" {
         break;
       }
 
-      fake_build_execute(data, data_build, data_build.setting.build_compiler, arguments, status);
+      fake_execute(data, data_build.environment, data_build.setting.build_compiler, arguments, status);
       if (F_status_is_error(*status)) break;
 
       f_macro_string_dynamics_delete_simple(arguments);
@@ -2471,7 +2427,7 @@ extern "C" {
       return;
     }
 
-    fake_build_execute(data, data_build, data_build.setting.build_compiler, arguments, status);
+    fake_execute(data, data_build.environment, data_build.setting.build_compiler, arguments, status);
 
     f_macro_string_dynamics_delete_simple(arguments);
 
@@ -2576,7 +2532,7 @@ extern "C" {
       return;
     }
 
-    fake_build_execute(data, data_build, data_build.setting.build_compiler, arguments, status);
+    fake_execute(data, data_build.environment, data_build.setting.build_compiler, arguments, status);
 
     f_macro_string_dynamics_delete_simple(arguments);
 
index 50a14a2614dc160d8c87f744b33ac9754261166a..6f0a8ae2086ff46eb036dfc35a22864a065c3562 100644 (file)
@@ -430,26 +430,6 @@ extern "C" {
 #endif // _di_fake_build_copy_
 
 /**
- * Execute the given command and arguments.
- *
- * Will print the command if in verbose mode.
- *
- * @param data
- *   The program data.
- * @param data_build
- *   The build data.
- * @param program
- *   The program to be executed.
- * @param arguments
- *   The arguments to be passed to the program.
- * @param status
- *   The return status.
- */
-#ifndef _di_fake_build_execute_
-  extern void fake_build_execute(const fake_data data, const fake_build_data data_build, const f_string_static program, const f_string_statics arguments, f_status *status) f_gcc_attribute_visibility_internal;
-#endif // _di_fake_build_execute_
-
-/**
  * Create all of the base directories inside the build directory.
  *
  * @param data
index 1e7f47a1b3a1d169ff9610891832e5fe322263b1..9b86ed8995c7f20ec6db7372b48581e2d185143c 100644 (file)
@@ -6,6 +6,50 @@
 extern "C" {
 #endif
 
+#ifndef _di_fake_execute_
+  void fake_execute(const fake_data data, const fake_environment environment, const f_string_static program, const f_string_statics arguments, f_status *status) {
+    if (F_status_is_error(*status)) return;
+
+    if (data.verbosity == fake_verbosity_verbose) {
+      printf("%s", program.string);
+
+      for (f_array_length i = 0; i < arguments.used; i++) {
+        if (arguments.array[i].used == 0) continue;
+
+        printf(" %s", arguments.array[i].string);
+      } // for
+
+      printf("%c", f_string_eol[0]);
+
+      // flush to stdout before executing command.
+      fflush(f_type_output);
+    }
+
+    {
+      int result = 0;
+
+      *status = fll_execute_program_environment(program.string, arguments, environment.names, environment.values, &result);
+
+      if (result != 0) {
+        *status = F_status_set_error(F_failure);
+      }
+      else if (F_status_is_error(*status)) {
+        if (F_status_set_fine(*status) == F_file_found_not) {
+          if (data.verbosity != fake_verbosity_quiet) {
+            fprintf(f_type_error, "%c", f_string_eol[0]);
+            fl_color_print(f_type_error, data.context.error, data.context.reset, "ERROR: Failed to find program '");
+            fl_color_print(f_type_error, data.context.notable, data.context.reset, "%s", program.string);
+            fl_color_print_line(f_type_error, data.context.error, data.context.reset, "' for executing.");
+          }
+        }
+        else {
+          fake_print_error(data, F_status_set_fine(*status), "fll_execute_program_environment", F_true);
+        }
+      }
+    }
+  }
+#endif // _di_fake_execute_
+
 #ifndef _di_fake_file_buffer_
   f_return_status fake_file_buffer(const fake_data data, const f_string path_file, f_string_dynamic *buffer) {
     f_file file = f_file_initialize;
index 820ba3995772316d269e770a39dd476961469fdc..0dcae9885bf1d8d5fdcb1ef3b06a2dc38877446f 100644 (file)
@@ -39,6 +39,26 @@ extern "C" {
 #endif // _di_fake_environment_
 
 /**
+ * Execute the given command and arguments.
+ *
+ * Will print the command if in verbose mode.
+ *
+ * @param data
+ *   The program data.
+ * @param environment
+ *   The environment variable data.
+ * @param program
+ *   The program to be executed.
+ * @param arguments
+ *   The arguments to be passed to the program.
+ * @param status
+ *   The return status.
+ */
+#ifndef _di_fake_execute_
+  extern void fake_execute(const fake_data data, const fake_environment environment, const f_string_static program, const f_string_statics arguments, f_status *status) f_gcc_attribute_visibility_internal;
+#endif // _di_fake_execute_
+
+/**
  * Load the contents of a file into the given buffer, handling all potential errors.
  *
  * @param data
index 24111bf3ac11559be1659ab3a0e9f7447764b315..a1f78d1e90f34c6aa349868ff2b308b207200c7a 100644 (file)
@@ -334,41 +334,34 @@ extern "C" {
         }
       }
 
+      f_string_range *range_compiler = 0;
+      f_string_range *range_linker = 0;
+
       data_make->setting_make.parameter.array[0].value.used = 1;
       data_make->setting_make.load_build = F_true;
       data_make->setting_make.fail = fake_make_operation_fail_type_exit;
 
       if (settings.objects.used) {
-        bool unmatched_load = F_true;
         bool unmatched_fail = F_true;
+        bool unmatched_load = F_true;
 
         for (f_array_length i = 0; i < settings.objects.used; i++) {
-          if (fl_string_dynamic_partial_compare_string(fake_make_setting_load_build, data_make->buffer, fake_make_setting_load_build_length, settings.objects.array[i]) == F_equal_to) {
-            if (unmatched_load) {
+          if (fl_string_dynamic_partial_compare_string(fake_make_setting_compiler, data_make->buffer, fake_make_setting_compiler_length, settings.objects.array[i]) == F_equal_to) {
+            if (range_compiler) {
+              fake_print_warning_settings_content_multiple(data, data.file_data_build_fakefile.string, fake_make_setting_compiler);
+            }
+            else {
               if (settings.contents.array[i].used) {
-                if (fl_string_dynamic_partial_compare_string(fake_common_setting_bool_yes, data_make->buffer, fake_common_setting_bool_yes_length, settings.contents.array[i].array[0]) == F_equal_to) {
-                  data_make->setting_make.load_build = F_true;
-                }
-                else if (fl_string_dynamic_partial_compare_string(fake_common_setting_bool_no, data_make->buffer, fake_common_setting_bool_no_length, settings.contents.array[i].array[0]) == F_equal_to) {
-                  data_make->setting_make.load_build = F_false;
-                }
-                else {
-                  fake_print_error_fakefile_settings_content_invalid(data, data.file_data_build_fakefile.string, data_make->buffer, settings.objects.array[i], settings.contents.array[i].array[0], fake_make_section_settings);
-                }
-
-                unmatched_load = F_false;
+                range_compiler = &settings.contents.array[i].array[0];
 
                 if (settings.contents.array[i].used > 1) {
-                  fake_print_warning_settings_content_multiple(data, data.file_data_build_fakefile.string, fake_make_setting_load_build);
+                  fake_print_warning_settings_content_multiple(data, data.file_data_build_fakefile.string, fake_make_setting_compiler);
                 }
               }
               else {
                 fake_print_error_fakefile_settings_content_empty(data, data.file_data_build_fakefile.string, data_make->buffer, settings.objects.array[i], fake_make_section_settings);
               }
             }
-            else {
-              fake_print_warning_settings_content_multiple(data, data.file_data_build_fakefile.string, fake_make_setting_load_build);
-            }
           }
           else if (fl_string_dynamic_partial_compare_string(fake_make_setting_fail, data_make->buffer, fake_make_setting_fail_length, settings.objects.array[i]) == F_equal_to) {
             if (unmatched_fail) {
@@ -400,6 +393,50 @@ extern "C" {
               fake_print_warning_settings_content_multiple(data, data.file_data_build_fakefile.string, fake_make_setting_fail);
             }
           }
+          else if (fl_string_dynamic_partial_compare_string(fake_make_setting_linker, data_make->buffer, fake_make_setting_linker_length, settings.objects.array[i]) == F_equal_to) {
+            if (range_linker) {
+              fake_print_warning_settings_content_multiple(data, data.file_data_build_fakefile.string, fake_make_setting_linker);
+            }
+            else {
+              if (settings.contents.array[i].used) {
+                range_linker = &settings.contents.array[i].array[0];
+
+                if (settings.contents.array[i].used > 1) {
+                  fake_print_warning_settings_content_multiple(data, data.file_data_build_fakefile.string, fake_make_setting_linker);
+                }
+              }
+              else {
+                fake_print_error_fakefile_settings_content_empty(data, data.file_data_build_fakefile.string, data_make->buffer, settings.objects.array[i], fake_make_section_settings);
+              }
+            }
+          }
+          else if (fl_string_dynamic_partial_compare_string(fake_make_setting_load_build, data_make->buffer, fake_make_setting_load_build_length, settings.objects.array[i]) == F_equal_to) {
+            if (unmatched_load) {
+              if (settings.contents.array[i].used) {
+                if (fl_string_dynamic_partial_compare_string(fake_common_setting_bool_yes, data_make->buffer, fake_common_setting_bool_yes_length, settings.contents.array[i].array[0]) == F_equal_to) {
+                  data_make->setting_make.load_build = F_true;
+                }
+                else if (fl_string_dynamic_partial_compare_string(fake_common_setting_bool_no, data_make->buffer, fake_common_setting_bool_no_length, settings.contents.array[i].array[0]) == F_equal_to) {
+                  data_make->setting_make.load_build = F_false;
+                }
+                else {
+                  fake_print_error_fakefile_settings_content_invalid(data, data.file_data_build_fakefile.string, data_make->buffer, settings.objects.array[i], settings.contents.array[i].array[0], fake_make_section_settings);
+                }
+
+                unmatched_load = F_false;
+
+                if (settings.contents.array[i].used > 1) {
+                  fake_print_warning_settings_content_multiple(data, data.file_data_build_fakefile.string, fake_make_setting_load_build);
+                }
+              }
+              else {
+                fake_print_error_fakefile_settings_content_empty(data, data.file_data_build_fakefile.string, data_make->buffer, settings.objects.array[i], fake_make_section_settings);
+              }
+            }
+            else {
+              fake_print_warning_settings_content_multiple(data, data.file_data_build_fakefile.string, fake_make_setting_load_build);
+            }
+          }
           else if (fl_string_dynamic_partial_compare_string(fake_make_setting_parameter, data_make->buffer, fake_make_setting_parameter_length, settings.objects.array[i]) == F_equal_to) {
             if (settings.contents.array[i].used) {
               if (fl_string_dynamic_partial_compare_string(fake_make_setting_return, data_make->buffer, fake_make_setting_return_length, settings.contents.array[i].array[0]) == F_equal_to) {
@@ -442,6 +479,31 @@ extern "C" {
 
       if (data_make->setting_make.load_build) {
         fake_build_load_setting(data, &data_make->setting_build, status);
+
+        if (F_status_is_error(*status)) {
+          fake_print_error(data, *status, "fake_build_load_setting", F_true);
+
+          f_macro_fss_set_delete_simple(settings);
+          return;
+        }
+      }
+
+      // if either compiler or linker is specified, each will replace any existing build_compiler or build_linker, respectively.
+      if (range_compiler) {
+        data_make->setting_build.build_compiler.used = 0;
+        *status = fl_string_dynamic_partial_append(data_make->buffer, *range_compiler, &data_make->setting_build.build_compiler);
+      }
+
+      if (F_status_is_fine(*status) && range_linker) {
+        data_make->setting_build.build_linker.used = 0;
+        *status = fl_string_dynamic_partial_append(data_make->buffer, *range_linker, &data_make->setting_build.build_linker);
+      }
+
+      if (F_status_is_error(*status)) {
+        fake_print_error(data, *status, "fl_string_dynamic_partial_append", F_true);
+
+        f_macro_fss_set_delete_simple(settings);
+        return;
       }
 
       f_string_map_multis define = f_string_map_multis_initialize;
@@ -1414,9 +1476,24 @@ extern "C" {
     if (F_status_is_error(*status)) return;
 
     if (operation == fake_make_operation_type_archive) {
-      // *status = fll_execute_arguments_add(values[i], lengths[i], &arguments);
-      //fake_build_arguments_standard_add(data, data_build, F_true, F_true, &arguments, status);
-      //fake_build_execute(data, data_build, data_build.setting.build_compiler, arguments, status);
+      if (data_make->setting_build.build_linker.used) {
+        fake_execute(data, data_make->environment, data_make->setting_build.build_linker, arguments, status);
+
+        if (F_status_is_error(*status)) {
+          fake_print_error(data, F_status_set_fine(*status), "fake_execute", F_true);
+          return;
+        }
+      }
+      else {
+        if (data.verbosity != fake_verbosity_quiet) {
+          fprintf(f_type_error, "%c", f_string_eol[0]);
+          fl_color_print(f_type_error, data.context.error, data.context.reset, "ERROR: No linker has been specified, cannot perform '");
+          fl_color_print(f_type_error, data.context.notable, data.context.reset, fake_make_operation_archive);
+          fl_color_print_line(f_type_error, data.context.error, data.context.reset, "' section operation.");
+        }
+
+        *status = F_status_set_error(F_failure);
+      }
 
       return;
     }
@@ -1436,9 +1513,25 @@ extern "C" {
     }
 
     if (operation == fake_make_operation_type_compile) {
-      // *status = fll_execute_arguments_add(values[i], lengths[i], &arguments);
-      //fake_build_arguments_standard_add(data, data_build, F_true, F_true, &arguments, status);
-      //fake_build_execute(data, data_build, data_build.setting.build_compiler, arguments, status);
+      if (data_make->setting_build.build_compiler.used) {
+        fake_execute(data, data_make->environment, data_make->setting_build.build_compiler, arguments, status);
+
+        if (F_status_is_error(*status)) {
+          fake_print_error(data, F_status_set_fine(*status), "fake_execute", F_true);
+          return;
+        }
+      }
+      else {
+        if (data.verbosity != fake_verbosity_quiet) {
+          fprintf(f_type_error, "%c", f_string_eol[0]);
+          fl_color_print(f_type_error, data.context.error, data.context.reset, "ERROR: No compiler has been specified, cannot perform '");
+          fl_color_print(f_type_error, data.context.notable, data.context.reset, fake_make_operation_compile);
+          fl_color_print_line(f_type_error, data.context.error, data.context.reset, "' section operation.");
+        }
+
+        *status = F_status_set_error(F_failure);
+      }
+
       return;
     }
 
@@ -1446,7 +1539,7 @@ extern "C" {
       // fake_make_assure_inside_project
       // *status = fll_execute_arguments_add(values[i], lengths[i], &arguments);
       //fake_build_arguments_standard_add(data, data_build, F_true, F_true, &arguments, status);
-      //fake_build_execute(data, data_build, data_build.setting.build_compiler, arguments, status);
+      //fake_execute(data, data_make->environment, data_build.setting.build_compiler, arguments, status);
       return;
     }
 
@@ -1459,7 +1552,7 @@ extern "C" {
       // fake_make_assure_inside_project
       // *status = fll_execute_arguments_add(values[i], lengths[i], &arguments);
       //fake_build_arguments_standard_add(data, data_build, F_true, F_true, &arguments, status);
-      //fake_build_execute(data, data_build, data_build.setting.build_compiler, arguments, status);
+      //fake_execute(data, data_make->environment, data_build.setting.build_compiler, arguments, status);
       return;
     }
 
@@ -1512,9 +1605,7 @@ extern "C" {
 
     if (operation == fake_make_operation_type_link) {
       // fake_make_assure_inside_project
-      // *status = fll_execute_arguments_add(values[i], lengths[i], &arguments);
-      //fake_build_arguments_standard_add(data, data_build, F_true, F_true, &arguments, status);
-      //fake_build_execute(data, data_build, data_build.setting.build_compiler, arguments, status);
+      // @todo: create symlink.
       return;
     }
 
index 683de3aba9e782d83268a7235b21b8ecb9c94596..495f7347016045e30c175029f9586a78414c1c83 100644 (file)
@@ -41,14 +41,18 @@ extern "C" {
   #define fake_macro_make_setting_delete_simple(setting) \
     f_macro_string_map_multis_delete_simple(setting.parameter)
 
+  #define fake_make_setting_compiler   "compiler"
   #define fake_make_setting_define     "define"
   #define fake_make_setting_fail       "fail"
+  #define fake_make_setting_linker     "linker"
   #define fake_make_setting_load_build "load_build"
   #define fake_make_setting_parameter  "parameter"
   #define fake_make_setting_return     "return"
 
+  #define fake_make_setting_compiler_length   8
   #define fake_make_setting_define_length     6
   #define fake_make_setting_fail_length       4
+  #define fake_make_setting_linker_length     6
   #define fake_make_setting_load_build_length 10
   #define fake_make_setting_parameter_length  9
   #define fake_make_setting_return_length     6
index 2ae12881c8800f5a32b29202956980779c305790..2263346f1e8f72c88ade1126f9c263a2deb58f4e 100644 (file)
@@ -4,6 +4,9 @@ settings:
   load_build yes
   fail exit
 
+  compiler gcc
+  linker ar
+
   parameter verbose +v
   parameter verbose_fll +V
 
index 78cf8dcc97dbff701263889663fc204a7e0d9de9..3ba3dd5586448255ba48ab3d04ffe0a72e18facb 100644 (file)
@@ -14,6 +14,9 @@ Fakefile Documentation:
     The build settings may also be specified in the Settings Section.
 
     The following settings are available (in addition to the build settings)\:
+    - compiler\:
+      This represents the name of the compiler program to use, such as "gcc".
+
     - define\:
       This represents an environment variable to define on run.
       The environment variable name is case-sensitive.
@@ -29,6 +32,9 @@ Fakefile Documentation:
 
       The return code for programs can still be retrieved through using the reserved iki vaiable "return".
 
+    - linker\:
+      This represents the name of the linker program to use, such as "ar".
+
     - load_build\:
       This represents whether or not to load the load the build settings file.
       The first Content value may be "true" to load the build settings and "false" to not load the build settings file.
@@ -74,13 +80,12 @@ Fakefile Documentation:
 
       The first Content must be either "file" or "directory".
       Use "file" to designate that this is a regular file being created.
-      The "directory" to designate that this is a directory file being created.
+      Use "directory" to designate that this is a directory file being created.
 
-      The second Content must be the file to be created.
+      The second Content must be the file to be created (be it a regular "file" or a "directory" file).
 
-      An optional third Content may be specified for "directory".
-      This third Content, if specified, may only be "recursive".
-      When specified, this will create all directories specified in the given directory file path.
+    - creates\:
+      Identical to "create", except that this will create all directories specified in the given directory file path.
 
     - define\:
       This represents an environment variable to define on run.
@@ -94,12 +99,12 @@ Fakefile Documentation:
       Use "file" to designate that this is a regular file being deleted.
       The "directory" to designate that this is a directory file being deleted.
 
-      The second Content must be the file to be created.
+      The second Content must be the file to be deleted.
+
+      When the first content is "directory" and that directory is not empty, then this will not delete the directory.
 
-      An optional third Content may be specified for "directory".
-      This third Content, if specified, may only be "recursive".
-      When specified, this will create all directories specified in the given directory file path.
-      If the directory is not empty, then "recursive" must be specified to delete the directory.
+    - deletes\:
+      Identical to "delete", except that when the first content is "directory" and that directory is not empty, then this will delete the directory.
 
     - else\:
       Performs a programmatic "else" condition.
index ad01f9ad9881940249721d8562f1d8bbf960cd17..328306f3a086731b6b9d26b8e3190e47767cf9b8 100644 (file)
@@ -33,6 +33,8 @@ Fakefile Specification:
   - main: contains a list of Operation Objects and Content in FSS-0001 (Extended) format.
 
   The Settings Objects are\:
+  - archiver: Only one Content, which must only be a valid filename.
+  - compiler: Only one Content, which must only be a valid filename.
   - define: First Content represents variable name (case-sensitive), remaining Content represents varaiable value for IKI substitution.
   - fail: Only one Content, which must be either "exit", "warn" or "ignore" (quotes not required) (case-sensitive).
   - load_build: Only one Content, which must be either "yes" or "no" (quotes not required) (case-sensitive).
@@ -45,9 +47,11 @@ Fakefile Specification:
   - build: Zero or One Content. First Content represents path to the settings file, relative to the project root.
   - clean: Zero Content.
   - compile: One or more Content as parameters to compiler.
-  - create: Two or three Content. First Content is either "file" or "directory" (case-sensitive), second Content is path to file, and third Content is "recursive" (case-sensitive) or is not provided.
+  - create: Two Content. First Content is either "file" or "directory" (case-sensitive), second Content is path to file.
+  - creates: Two Content. First Content is either "file" or "directory" (case-sensitive), second Content is path to file.
   - define: Two or more Content.
-  - delete: Two or three Content. First Content is either "file" or "directory" (case-sensitive), second Content is path to file, and third Content is "recursive" (case-sensitive) or is not provided.
+  - delete: One or more Content representing paths to files.
+  - deletes: One or more Content representing paths to files.
   - else: Zero Content.
   - fail: One Content. First Content must be one of "exit", "warn", or "ignore" (case-sensitive).
   - group: Two or more Content. First Content is group name or number, remaining Content are paths to files.