syntax = "proto3";

package cmd;

import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";

// A command to execute locally or remotely.
message Command {
  // Identifiers used to identify this command to be passed to RE.
  Identifiers identifiers = 1;

  // An absolute path to the execution root of the command. All the other paths are
  // specified relatively to this path.
  string exec_root = 2;

  // The command inputs.
  InputSpec input = 3;

  // The command outputs.
  OutputSpec output = 4;

  // Command line elements to execute.
  repeated string args = 5;

  // If > 0, the maximum number of seconds to wait for command execution
  // before timing out.
  int32 execution_timeout = 6;

  // The working directory, relative to the exec root, for the command to run
  // in. It must be a directory which exists in the input tree. If it is left
  // empty, then the action is run in the exec root.
  string working_directory = 7;

  // The platform to use for the remote execution.
  map<string,string> platform = 8;

  // The working directory when executing the command on RE server.
  // It's relative to exec root and, if provided, needs to have the same number of levels
  // as WorkingDir. If not provided, the remote command is run from the WorkingDir
  string remote_working_directory = 9;
}

// Identifiers identifying a command that are passed to the remote server for logging.
message Identifiers {
  // An optional id to use to identify a command.
  string command_id = 1;

  // An optional id to use to identify an invocation.
  string invocation_id = 2;

  // An optional id to use to identify a build.
  string correlated_invocations_id = 3;

  // An optional tool name to pass to the remote server for logging.
  string tool_name = 4;

  // An optional tool version to pass to the remote server for logging.
  string tool_version = 5;

  // An optional ID identifying a particular execution of this command.
  string execution_id = 6;
}

message InputType {
  enum Value {
     // Any type will match.
     UNSPECIFIED = 0;
     // Only directories match.
     DIRECTORY = 1;
     // Only files match.
     FILE = 2;
  }
}

message ExcludeInput {
  // If an input matches this regular expression, ignore it.
  string regex = 1;
  // If an input path has this type, ignore it.
  InputType.Value type = 2;
}

// VirtualInput represents an input that may exist on disk but shouldn't be accessed.
// We want to stage it on disk for the command execution.
message VirtualInput {
  // The path for the input file to be staged at, relative to the ExecRoot.
  string path = 1;
  // The byte contents of the file to be staged.
  bytes contents = 2;
  // Whether the file should be staged as executable.
  bool is_executable = 3;
  // Whether the input is an empty directory.
  bool is_empty_directory = 4;
  // The digest of the virtual input that is expected to exist in the CAS.
  string digest = 5;
  // Mtime of the virtual input represented as a Unix Timestamp.
  google.protobuf.Timestamp mtime = 6;
  // The virtual inputs' mode and permissions bits.
  uint32 filemode = 7;
}

message SymlinkBehaviorType {
  enum Value {
    // Use Client.TreeSymlinkOpts or default if it is not set.
    UNSPECIFIED = 0;
    // Resolves symlinks.
    RESOLVE = 1;
    // Preserve symlinks as-is.
    PRESERVE = 2;
  }
}

message InputSpec {
  // Input paths (files or directories) that need to be uploaded to the remote
  // server for the command execution.
  // Note: a known limitation of the first version of the proxy is that for any
  // *directory* inputs, the contents of the directory will only be read once,
  // and then cached throughout the proxy lifetime. Any subsequent changes to the
  // directory will therefore not be captured.
  repeated string inputs = 2;

  // Virtual inputs that need to be staged as if they were present on disk.
  repeated VirtualInput virtual_inputs = 5;

  // Inputs matching these patterns will be excluded (not uploaded remotely).
  repeated ExcludeInput exclude_inputs = 3;

  // Environment variables the command relies on.
  map<string,string> environment_variables = 4;

  // Determines how symlinks should be treated when constructing the input tree.
  SymlinkBehaviorType.Value symlink_behavior = 6;

  // Node properties of inputs.
  map<string,NodeProperties> input_node_properties = 7;
}

// A copy of NodeProperties from https://github.com/bazelbuild/remote-apis/blob/main/build/bazel/remote/execution/v2/remote_execution.proto
// to avoid importing it as a proto dependency.
// Importing the messages causes resource exhaustion on high parallelism builds.
message NodeProperties {
  // A list of string-based
  // [NodeProperties][build.bazel.remote.execution.v2.NodeProperty].
  repeated NodeProperty properties = 1;

  // The file's last modification timestamp.
  google.protobuf.Timestamp mtime = 2;

  // The UNIX file mode, e.g., 0755.
  google.protobuf.UInt32Value unix_mode = 3;
}

// A copy of NodeProperty from https://github.com/bazelbuild/remote-apis/blob/main/build/bazel/remote/execution/v2/remote_execution.proto
// to avoid importing it as a proto dependency.
// Importing the messages causes resource exhaustion on high parallelism builds.
message NodeProperty {
    // The property name.
    string name = 1;

    // The property value.
    string value = 2;
}

message OutputSpec {
  // Output files relative to working directory generated by the command.
  repeated string output_files = 1;

  // Output directories relative to working directory generated by the command.
  repeated string output_directories = 2;
}

message CommandResultStatus {
  enum Value {
    // Default case. Should not be used.
    UNKNOWN = 0;
    // Command executed successfully.
    SUCCESS = 1;
    // The command did not execute and a previously cached result was
    // retrieved.
    CACHE_HIT = 2;
    // The command executed with a non zero exit code.
    NON_ZERO_EXIT = 3;
    // The command timed out.
    TIMEOUT = 4;
    // The command was interrupted.
    INTERRUPTED = 5;
    // Execution of the command failed due to a remote execution error.
    REMOTE_ERROR = 6;
    // Execution of the command failed due to a local execution error.
    LOCAL_ERROR = 7;
  }
}

// Result of a command execution returned by the proxy.
message CommandResult {
  // Status of the finished run.
  CommandResultStatus.Value status = 1;

  // Command exit code.
  int32 exit_code = 2;

  // Optional exception trace or other message that should be displayed.
  string msg = 3;
}

// TimeInterval is used to serialize the SDK TimeInterval struct.
message TimeInterval {
  google.protobuf.Timestamp from = 1;
  google.protobuf.Timestamp to = 2;
}
