# Copyright (c) 2022 Firebuild Inc.
# All rights reserved.
# Free for personal use and commercial trial.
# Non-trial commercial use requires licenses available from https://firebuild.com.
# Modification and redistribution are permitted, but commercial use of
# derivative works is subject to the same requirements of this license
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

# This is the definition of the FBB format used for storing the cache
# entries.

# This is a Python dictionary, to be read and processed by "generate_fbb".

{
  "types_with_custom_debugger": ["mode_t", "firebuild::FileType", "XXH128_hash_t"],

  "extra_c": """
    /* Debugger method for mode_t fields. */
    static void fbbstore_debug_mode_t(FILE *f, mode_t mode) {
      fprintf(f, "\\"");
      debug_mode_t(f, mode);
      fprintf(f, "\\"");
    }

    /* Debugger method for firebuild::FileType fields. */
    static void fbbstore_debug_firebuild__FileType(FILE *f, firebuild::FileType type) {
      fprintf(f, "\\"%s\\"", file_type_to_string(type));
    }

    /* Debugger method for XXH128_hash_t fields. */
    static void fbbstore_debug_XXH128_hash_t(FILE *f, XXH128_hash_t value) {
      firebuild::Hash hash(value);
      char ascii[firebuild::Hash::kAsciiLength + 1];
      hash.to_ascii(ascii);
      fprintf(f, "\\"%s\\"", ascii);
    }
  """,

  "extra_h": """
    #include <xxhash.h>
    #include "firebuild/hash.h"
    #include "firebuild/file_info.h"
    #include "common/debug_sysflags.h"
  """,

  "tags": [
    ("file", [
      # file path, absolute or relative
      (REQUIRED, STRING,                "path"),

      # file type, e.g. ISREG, NOTEXIST_OR_ISREG, ISDIR etc.
      (REQUIRED, "firebuild::FileType", "type"),
      # file size
      (OPTIONAL, "size_t",              "size"),
      # checksum (binary) of the file content, if relevant and known
      (OPTIONAL, "XXH128_hash_t",       "hash"),
      # TODO add alternate hash values generated after preprocessing the file
      # with programs keeping the semantic content (e.g. removing white spaces)
      #(OPTIONAL, "XXH128_hash_t",       "alt_hash"),

      # last modification time - FIXME in what unit?
      #(OPTIONAL, "long",                "mtime"),
      # the known bits of the mode, if any
      (OPTIONAL, "mode_t",              "mode"),
      # which bits of the mode are known, if any
      (OPTIONAL, "mode_t",              "mode_mask"),
      # The reason why the file could not be opened.
      #(OPTIONAL, "int",                 "error_no"),
    ]),

    ("dir", [
      (REQUIRED, STRING, "path"),
      (ARRAY,    STRING, "entry"),
    ]),

    ("append_to_fd", [
      # fd at the time the process started, the lowest one if dup()'ed to
      # multiple fds
      (REQUIRED, "int",           "fd"),
      # Checksum (binary) of the written data
      (REQUIRED, "XXH128_hash_t", "hash"),
    ]),

    # Things that are read from the external world by the process while
    # it's running, but aren't known in advance that the process will need
    # them. In order to shortcut a process, there has to be a cached entry
    # that matches the current world.
    ("process_inputs", [
      # Files that are opened for reading, with various results.
      (ARRAY, FBB,    "path"),                         # tag "file"
      (ARRAY, STRING, "path_notexist"),

      # TODO: Directories that are opendir'ed, even if opendir failed.
      # FIXME: need to fingerprint the entire directory listing??
      #(ARRAY, FBB,    "path_isdir_listed"),            # tag "dir"

      # TODO: readlink and friends...
    ]),

    # Things that are modified in the external world by the process while
    # it's running.
    ("process_outputs", [
      # Files that are written to (or removed), only if opening them for
      # writing succeeded.
      (ARRAY,    FBB,    "path_isreg"),            # tag "file"
      # Directories created
      (ARRAY,    FBB,    "path_isdir"),            # tag "file"
      (ARRAY,    STRING, "path_notexist"),
      # Maybe special handling of files that are appended to?

      # TODO:
      # unlink, rmdir
      # link, symlink
      # chown, chmod
      # etc.

      # Data appended to inherited files (currently pipes only)
      (ARRAY,    FBB,    "append_to_fd"),          # tag "append_to_fd"

      (REQUIRED, "int",  "exit_status"),
    ]),

    ("process_inputs_outputs", [
      (REQUIRED, FBB,    "inputs"),                # tag "process_inputs"
      (REQUIRED, FBB,    "outputs"),               # tag "process_outputs"
      # Aggregate CPU time used by this process and all children in milliseconds.
      # Not set when deterministic cache debugging is enabled.
      (OPTIONAL, "int",  "cpu_time_ms"),
    ]),
  ]
}
