let save ~name thing =     let open KEDSL in     let basename = Filename.basename in     let canonicalize path =       (* Remove the ending '/' from the path. This is so rsync syncs the directory itself +  *)       let suffix = "/" in       if Filename.check_suffix path suffix       then String.chop_suffix_exn ~suffix path       else path     in     let base_path =       Saving_utilities.base_path         ?results_dir:Config.results_dir ~work_dir:Config.work_dir ~name () in     let move ?(and_gzip = false) ~from_path ~wf product =       let json =         `Assoc [           "base-path"`String base_path;           "saved-from"`String from_path;           "provenance",           AF.get_provenance thing |> Provenance_description.to_yojson;         ]         |> Yojson.Basic.pretty_to_string       in       let make =         Machine.quick_run_program           Config.machine           Program.(             shf "mkdir -p %s" base_path             && shf "rsync -a %s %s" from_path base_path             && (               match and_gzip with               | true ->                 shf "for f in $(find %s -type f) ; do gzip --force --keep $f ; done" base_path               | false -> sh "echo 'No GZipping Requested'"             )             && shf "echo %s > %s.json" (Filename.quote json) base_path           )       in       let name = sprintf "Saving \"%s\"" name in       workflow_node product ~name ~make ~edges:[depends_on wf]     in     let tf path = transform_single_file ~path in     begin match AF.get_file thing with     | Bam wf ->       let from_path = wf#product#path in       let to_path = base_path // basename from_path in       Bam (move ~from_path ~wf (transform_bam ~path:to_path wf#product))     | Vcf wf ->       let from_path = wf#product#path in       let to_path = base_path // basename from_path in       Vcf (move ~and_gzip:true ~from_path ~wf              (transform_vcf ~path:to_path wf#product))     | Gtf wf ->       let from_path = wf#product#path in       let to_path = base_path // basename from_path in       Gtf (move ~from_path ~wf (tf to_path wf#product))     | Flagstat_result wf ->       let from_path = wf#product#path in       let to_path = base_path // basename from_path in       Flagstat_result (move ~from_path ~wf (tf to_path wf#product))     | Isovar_result wf ->       let from_path = wf#product#path in       let to_path = base_path // basename from_path in       Isovar_result (move ~from_path ~wf (tf to_path wf#product))     | Topiary_result wf ->       let from_path = wf#product#path in       let to_path = base_path // basename from_path in       Topiary_result (move ~from_path ~wf (tf to_path wf#product))     | Vaxrank_result wf ->       let from_path = canonicalize wf#product#output_folder_path in       let to_path = base_path // basename from_path in       let vp =         Tools.Vaxrank.move_vaxrank_product           ~output_folder_path:to_path wf#product       in       Vaxrank_result (move ~from_path ~wf vp)     | Optitype_result wf ->       let from_path = wf#product#path in       let to_path = base_path // basename from_path in       let o =         Tools.Optitype.move_optitype_product ~path:to_path wf#product       in       let from_path = wf#product#path in       Optitype_result (move ~from_path ~wf o)     | Seq2hla_result wf ->       let from_path = canonicalize wf#product#work_dir_path in       let to_path = base_path // basename from_path in       let s =         Tools.Seq2HLA.move_seq2hla_product ~path:to_path wf#product       in       Seq2hla_result (move ~from_path ~wf s)     | Fastqc_result wf ->       let from_path =         wf#product#paths |> List.hd_exn |> Filename.dirname |> canonicalize in       let fqc =         let paths = List.map wf#product#paths             ~f:(fun p ->                 base_path                 // (basename from_path)                 // (basename p)) in         list_of_files paths       in       Fastqc_result (move ~from_path ~wf fqc)     | Cufflinks_result wf ->       let from_path = wf#product#path in       let to_path = base_path // basename from_path in       Cufflinks_result (move ~from_path ~wf (tf to_path wf#product))     | Bai wf ->       let from_path = wf#product#path in       let to_path = base_path // basename from_path in       Bai (move ~from_path ~wf (tf to_path wf#product))     | Kallisto_result wf ->       let from_path = wf#product#path in       let to_path = base_path // basename from_path in       Kallisto_result (move ~from_path ~wf (tf to_path wf#product))     | MHC_alleles wf ->       let from_path = wf#product#path in       let to_path = base_path // basename from_path in       MHC_alleles (move ~from_path ~wf (tf to_path wf#product))     | Raw_file wf ->       let from_path = canonicalize wf#product#path in       let to_path = base_path // basename from_path in       Raw_file (move ~from_path ~wf (tf to_path wf#product))     | Gz _ -> failwith "Cannot `save` Gz."     | List _ -> failwith "Cannot `save` List."     | Pair _ -> failwith "Cannot `save` Pair."     | Lambda _ -> failwith "Cannot `save` Lambda."     | _ -> failwith "Shouldn't get here: pattern match for `save` must be exhaustive."     end     |> AF.with_provenance "save"       ["product"AF.get_provenance thing]       ~string_arguments:["name", name]