src/Pure/General/rsync.scala
author wenzelm
Sun, 11 Dec 2022 11:47:28 +0100
changeset 76616 e6c11ef4fb51
parent 76170 5912209b4fb6
child 76617 d5adc9126ae8
permissions -rw-r--r--
tuned signature;

/*  Title:      Pure/General/rsync.scala
    Author:     Makarius

Support for rsync: see also https://rsync.samba.org
*/

package isabelle


object Rsync {
  sealed case class Context(progress: Progress,
    ssh_port: Int = 0,
    ssh_control_path: String = "",
    archive: Boolean = true,
    protect_args: Boolean = true  // requires rsync 3.0.0, or later
  ) {
    def command: String = {
      val ssh_command = SSH.client_command(port = ssh_port, control_path = ssh_control_path)
      "rsync --rsh=" + Bash.string(ssh_command) +
        (if (archive) " --archive" else "") +
        (if (protect_args) " --protect-args" else "")
    }
  }

  def exec(
    context: Context,
    verbose: Boolean = false,
    thorough: Boolean = false,
    prune_empty_dirs: Boolean = false,
    dry_run: Boolean = false,
    clean: Boolean = false,
    list: Boolean = false,
    filter: List[String] = Nil,
    args: List[String] = Nil
  ): Process_Result = {
    val script =
      context.command +
        (if (verbose) " --verbose" else "") +
        (if (thorough) " --ignore-times" else " --omit-dir-times") +
        (if (prune_empty_dirs) " --prune-empty-dirs" else "") +
        (if (dry_run) " --dry-run" else "") +
        (if (clean) " --delete-excluded" else "") +
        (if (list) " --list-only --no-human-readable" else "") +
        filter.map(s => " --filter=" + Bash.string(s)).mkString +
        (if (args.nonEmpty) " " + Bash.strings(args) else "")
    context.progress.bash(script, echo = true)
  }

  def init(context: Context, target: String,
    contents: List[File.Content] = Nil
  ): Unit =
    Isabelle_System.with_tmp_dir("sync") { tmp_dir =>
      val init_dir = Isabelle_System.make_directory(tmp_dir + Path.explode("init"))
      contents.foreach(_.write(init_dir))
      exec(context.copy(archive = false),
        thorough = true,
        args =
          List(if (contents.nonEmpty) "--archive" else "--dirs",
            File.bash_path(init_dir) + "/.", target)).check
    }

  def direct(prefix: String): String =
    if (prefix.endsWith(":") || prefix.endsWith("/")) prefix + "."
    else if (prefix.endsWith(":.") || prefix.endsWith("/.")) prefix
    else prefix + "/."

  def append(prefix: String, suffix: String): String =
    if (prefix.endsWith(":") || prefix.endsWith("/")) prefix + suffix
    else prefix + "/" + suffix
}