The hardware and bandwidth for this mirror is donated by METANET, the Webhosting and Full Service-Cloud Provider.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]metanet.ch.

Symlink Tool Technical Vignette

Other Features

Other available features will be covered briefly, and will assume the reader has already read the Symlink Tool Intro section.

Mark Keep

It’s likely you’ll have other output versions you want to keep, but not as ‘best’. You can mark these as ‘keep’.

suppressMessages(
  slt$mark_keep(version_name = "2024_02_10", user_entry = list(comment = "testing mark_keep"))
)
print_tree(root_base)
#> |-- log_symlinks_central.csv
#> |-- modeled
#> |  |-- 2024_02_02
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- 2024_02_10
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- keep_2024_02_10
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  `-- report_key_versions.csv
#> `-- to_model
#>    |-- 2024_02_02
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- 2024_02_10
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- keep_2024_02_10
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    `-- report_key_versions.csv
print_symlink("keep")
#> [1] "lrwxrwxrwx 1 ssbyrne Domain Users   39 Jul 24 11:13 keep_2024_02_10 -> /tmp/Rtmp3tDGBK/slt/to_model/2024_02_10"

Reports pt 2

In addition to the report_key_versions.csv file, there are other reports available. These will show the status of the last log row for each version_name folder in each root folder.

You can view things like:

NOTE: This includes a discrepancy report that shows if logs do not conform to expected standards.

# Show the types of reports currently available
slt$make_reports
#> function () 
#> {
#>     private$msg_sometimes("Writing last-row log reports for:\n")
#>     for (root in private$DICT$ROOTS) {
#>         private$msg_sometimes("  ", root)
#>         private$report_all_logs(root = root)
#>         private$report_all_logs_symlink(root = root)
#>         private$report_all_logs_tool_symlink(root = root)
#>         private$report_all_logs_non_symlink(root = root)
#>         private$report_discrepancies(root = root, verbose = FALSE)
#>         private$msg_sometimes("  ", root)
#>     }
#> }
#> <environment: 0x55d711ad6088>
# Run the reports
suppressMessages({
  slt$make_reports()
})
print_tree(root_base)
#> |-- log_symlinks_central.csv
#> |-- modeled
#> |  |-- 2024_02_02
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- 2024_02_10
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- keep_2024_02_10
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- report_all_logs.csv
#> |  |-- report_all_logs_non_symlink.csv
#> |  |-- report_all_logs_symlink.csv
#> |  `-- report_key_versions.csv
#> `-- to_model
#>    |-- 2024_02_02
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- 2024_02_10
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- keep_2024_02_10
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- report_all_logs.csv
#>    |-- report_all_logs_non_symlink.csv
#>    |-- report_all_logs_symlink.csv
#>    `-- report_key_versions.csv
# View an example report - logs for folders with no active symlink
# - you can see this folder was previously marked 'best'
data.table::fread(file.path(root_input, "report_all_logs_non_symlink.csv"))
#>    log_id         timestamp    user version_name                            version_path      action           comment
#>     <int>            <char>  <char>       <char>                                  <char>      <char>            <char>
#> 1:      2 2025_07_24_111339 ssbyrne   2024_02_02 /tmp/Rtmp3tDGBK/slt/to_model/2024_02_02 demote_best testing mark_best
# Expect this to be absent for the vignette
try(data.table::fread(file.path(root_input, "REPORT_DISCREPANCIES.csv")))
#> Error in data.table::fread(file.path(root_input, "REPORT_DISCREPANCIES.csv")) : 
#>   File '/tmp/Rtmp3tDGBK/slt/to_model/REPORT_DISCREPANCIES.csv' does not exist or is non-readable. getwd()=='/tmp/RtmpBjZYIf/Rbuild3a7bce4ab1354e/vmTools/vignettes'

Roundups

Let’s say you have a set of folders you want to keep or remove, and you want to do it all at once.

We’ll demonstrate by:

  1. Making a set of dummy folders
    1. Marking some as remove_
      1. Rounding up the remove_ folders for deletion
    2. Round up the rest by date
      1. Mark these as keep_
# Make a set of dummy folders
dv1  <- get_output_dir(root_input,  "today")
slt$make_new_version_folder(dv1)
dv2  <- get_output_dir(root_input,  "today")
slt$make_new_version_folder(dv2)
dv3  <- get_output_dir(root_input,  "today")
slt$make_new_version_folder(dv3)
dv4  <- get_output_dir(root_input,  "today")
slt$make_new_version_folder(dv4)

print_tree(root_base)
#> |-- log_symlinks_central.csv
#> |-- modeled
#> |  |-- 2024_02_02
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- 2024_02_10
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- 2025_07_24.01
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- 2025_07_24.02
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- 2025_07_24.03
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- 2025_07_24.04
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- keep_2024_02_10
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- report_all_logs.csv
#> |  |-- report_all_logs_non_symlink.csv
#> |  |-- report_all_logs_symlink.csv
#> |  `-- report_key_versions.csv
#> `-- to_model
#>    |-- 2024_02_02
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- 2024_02_10
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- 2025_07_24.01
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- 2025_07_24.02
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- 2025_07_24.03
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- 2025_07_24.04
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- keep_2024_02_10
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- report_all_logs.csv
#>    |-- report_all_logs_non_symlink.csv
#>    |-- report_all_logs_symlink.csv
#>    `-- report_key_versions.csv

roundup_remove

# Mark some as 'remove_'
suppressMessages({
  for(dv in c(dv1, dv2)){
    slt$mark_remove(dv, user_entry = list(comment = "mark_remove for roundup"))
  }
})
# Round up and delete
roundup_remove_list <- slt$roundup_remove()
suppressMessages({
  for(dv in roundup_remove_list$root_input$version_name){
    slt$delete_version_folders(
      version_name       = dv,
      user_entry         = list(comment = "roundup_remove"),
      require_user_input = FALSE
    )
  }
})
print_tree(root_base)
#> |-- log_symlinks_central.csv
#> |-- modeled
#> |  |-- 2024_02_02
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- 2024_02_10
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- 2025_07_24.03
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- 2025_07_24.04
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- keep_2024_02_10
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- report_all_logs.csv
#> |  |-- report_all_logs_non_symlink.csv
#> |  |-- report_all_logs_symlink.csv
#> |  `-- report_key_versions.csv
#> `-- to_model
#>    |-- 2024_02_02
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- 2024_02_10
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- 2025_07_24.03
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- 2025_07_24.04
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- keep_2024_02_10
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- report_all_logs.csv
#>    |-- report_all_logs_non_symlink.csv
#>    |-- report_all_logs_symlink.csv
#>    `-- report_key_versions.csv

roundup_by_date

Use the log creation date (first row) to round up folders created on, before, or after that date.

my_date <- format(Sys.Date(), "%Y_%m_%d")
roundup_date_list <- slt$roundup_by_date(
  user_date     = my_date,
  date_selector = "lte" # less than or equal to today's date
)
#> Finding all folders with log creation dates that are 'lte' 2025_07_24. 
#>   NOTE! Log creation dates are used as the file-system does not record creation times.
#> roundup_by_date: Formatting date with time-zone: America/Los_Angeles
#> Folders with symlinks will have duplicate rows by `version_name` (one row for each unique `dir_name`) - showing all for completeness.
# mark all our dummy folders (with the ".VV" pattern) as keepers
dv_keep <- grep(
  pattern = "\\.\\d\\d"
  , x     = roundup_date_list$root_input$version_name
  , value = TRUE
)
suppressMessages({
  for(dv in dv_keep){
    slt$mark_keep(dv, user_entry = list(comment = "roundup_by_date"))
  }
})
print_tree(root_base)
#> |-- log_symlinks_central.csv
#> |-- modeled
#> |  |-- 2024_02_02
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- 2024_02_10
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- 2025_07_24.03
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- 2025_07_24.04
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- keep_2024_02_10
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- keep_2025_07_24.03
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- keep_2025_07_24.04
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- report_all_logs.csv
#> |  |-- report_all_logs_non_symlink.csv
#> |  |-- report_all_logs_symlink.csv
#> |  `-- report_key_versions.csv
#> `-- to_model
#>    |-- 2024_02_02
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- 2024_02_10
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- 2025_07_24.03
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- 2025_07_24.04
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- keep_2024_02_10
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- keep_2025_07_24.03
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- keep_2025_07_24.04
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- report_all_logs.csv
#>    |-- report_all_logs_non_symlink.csv
#>    |-- report_all_logs_symlink.csv
#>    `-- report_key_versions.csv

Make new log

The date roundup relies on the log creation date (recall, the Linux filesystem does not record folder creation / birth dates). If you’ve made your own folders without the symlink tool, you can make a blank log easily. You can hand-edit the creation date if you know when the folder was made.

Note:

# Make a naive folder without a log
dir.create(file.path(root_output, "2024_02_10_naive"))
try(slt$make_new_log(version_name = "2024_02_10_naive"))
print_tree(root_base)
#> |-- log_symlinks_central.csv
#> |-- modeled
#> |  |-- 2024_02_02
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- 2024_02_10
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- 2024_02_10_naive
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- 2025_07_24.03
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- 2025_07_24.04
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- keep_2024_02_10
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- keep_2025_07_24.03
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- keep_2025_07_24.04
#> |  |  `-- logs
#> |  |     `-- log_version_history.csv
#> |  |-- report_all_logs.csv
#> |  |-- report_all_logs_non_symlink.csv
#> |  |-- report_all_logs_symlink.csv
#> |  `-- report_key_versions.csv
#> `-- to_model
#>    |-- 2024_02_02
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- 2024_02_10
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- 2024_02_10_naive
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- 2025_07_24.03
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- 2025_07_24.04
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- keep_2024_02_10
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- keep_2025_07_24.03
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- keep_2025_07_24.04
#>    |  `-- logs
#>    |     `-- log_version_history.csv
#>    |-- report_all_logs.csv
#>    |-- report_all_logs_non_symlink.csv
#>    |-- report_all_logs_symlink.csv
#>    `-- report_key_versions.csv

Internal State

You can audit the internal state of the tool with the print_ functions.

# Print all static fields (output truncated)
slt$return_dictionaries()
#> $FLAGS
#> $FLAGS$allow_schema_repair
#> [1] TRUE
#> 
#> 
#> $ROOTS
#> $ROOTS$root_input
#> [1] "/tmp/Rtmp3tDGBK/slt/to_model"
#> 
#> $ROOTS$root_output
#> [1] "/tmp/Rtmp3tDGBK/slt/modeled"
....
#> [1] "^best"
#> 
#> $symlink_regex_extract$keep
#> [1] "^keep_"
#> 
#> $symlink_regex_extract$remove
#> [1] "^remove_"
#> 
#> 
#> $verbose
#> [1] TRUE
# ROOTS are likely most interesting to the user.
slt$return_dictionaries(item_names = "ROOTS")
#> $ROOTS
#> $ROOTS$root_input
#> [1] "/tmp/Rtmp3tDGBK/slt/to_model"
#> 
#> $ROOTS$root_output
#> [1] "/tmp/Rtmp3tDGBK/slt/modeled"
# Show the last 'action' the tool performed
# - these fields are set as part of each 'marking' new action.
slt$return_dynamic_fields()
#> $LOG
#> $LOG$version_name
#> [1] "2024_02_10_naive"
#> 
#> $LOG$action
#> [1] "promote_keep"
#> 
#> 
#> $VERS_PATHS
#> $VERS_PATHS$root_input
#> [1] "/tmp/Rtmp3tDGBK/slt/to_model/2024_02_10_naive"
#> 
#> $VERS_PATHS$root_output
#> [1] "/tmp/Rtmp3tDGBK/slt/modeled/2024_02_10_naive"

Clean Up

# Finally, clean up all our temporary folders
system(paste("rm -rf", root_base))

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.