make_filenames_safe.sf 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. #!/usr/bin/ruby
  2. # Make filenames portable to almost any filesystem
  3. Sig.__WARN__ { |msg| die msg } # make warnings fatal
  4. var f = frequire('File::Find')
  5. var u = frequire('Text::Unidecode')
  6. var rename = false
  7. # Check first argument
  8. if (ARGV[0] == '-r') {
  9. ARGV.shift
  10. rename = true
  11. }
  12. var dirs = ARGV || die "usage: #{__MAIN__} [-r] [dirs|files]\n"
  13. f.find(
  14. Hash(
  15. wanted => func(arg) {
  16. var file = File(Str(arg).decode_utf8)
  17. if (file.is_file) {
  18. # Ignore hidden files and directories
  19. if (file.split.any { .begins_with('.') }) {
  20. return nil
  21. }
  22. # Get dirname and basename
  23. var basename = file.basename
  24. var dirname = file.dirname
  25. # Unidecode and remove unsafe characters
  26. basename.gsub!(/[^\w\s[:punct:]]/, '')
  27. basename = u.unidecode(basename)
  28. basename.gsub!(/[^A-Za-z0-9_.-]+/, ' ')
  29. # Get away the extension (if any)
  30. var ext = ''
  31. if (var match = (basename =~ /(\.\w{1,5})\z/)) {
  32. ext = match.cap[0]
  33. basename.substr!(0, -ext.len)
  34. }
  35. # Replace any dot with a space
  36. basename.gsub!(/\.+/, ' ')
  37. # Squeeze more spaces into one space char
  38. basename = basename.words.join(' ')
  39. # Trim filename to 255 characters (if longer)
  40. if (basename.length > (255 - ext.len)) {
  41. basename.substr!(0, 255 - ext.len).trim_end!
  42. }
  43. # Append back the extension
  44. basename += ext
  45. # Create the new filename
  46. var new_file = (dirname + basename)
  47. # Rename the old filename to the new filename
  48. if (new_file != file) {
  49. say "Renaming: `#{file}' -> `#{new_file}'"
  50. if (File.exists(new_file)) {
  51. STDERR.print("\t...file already exists!\n")
  52. }
  53. elsif (rename) {
  54. File.rename(file, new_file) || (
  55. STDERR.print("\tcan't rename it: #{$!}\n")
  56. )
  57. }
  58. }
  59. }
  60. },
  61. no_chdir => 0,
  62. ), dirs.map { File(_).is_dir ? Dir(_) : File(_) }.map { .rel2abs }...
  63. )