Недавно развернул для производственных нужд на работе сервер Gitlab — открытый аналог github.com. Всё бы хорошо, но мы — троглодиты такие — до сих пор пишем код прошивок для наших девайсов под gcc, который не понимает юникод. Поэтому файлы с русскими комментариями сохраняются в кодировке Windows-1251. А Gitlab как-то странно их показывает. Примерно так:
static inline char EncodeCharRuc(char symbol)
{
if(symbol == 0xA8) //бшьтюы 'Ј'
return 0xA2;
else if(symbol == 0xB8) //бшьтюы 'И'
return 0xB5;
else if((symbol >= 0xC0) && (symbol <= 0xFF)) //бшьтюыћ №ѓёёъюую рыєртшђр ъ№юьх 'И' ш 'Ј'
return HD44780_table_code[symbol-0xC0];
else //Тёх юёђрыќэћх ёшьтюыћ
return symbol;
}
Использован отрывок кода моего коллеги UniBomb‘a
Ruby-гем charlock_holmes
, отвечающий за распознавание кодировки исходников и перевода их в UTF-8, почему-то не может сам понять, что подсовывают ему именно Windows-1251. Пришлось ему помочь.
Вот оригинальный файл модуля encode.rb:
# Patch Strings to enable detect_encoding! on views require 'charlock_holmes/string' module Gitlab module Encode extend self def utf8 message # return nil if message is nil return nil unless message message.force_encoding("utf-8") # return message if message type is binary detect = CharlockHolmes::EncodingDetector.detect(message) return message if detect[:type] == :binary # if message is utf-8 encoding, just return it return message if message.valid_encoding? # if message is not utf-8 encoding, convert it if detect[:encoding] message.force_encoding(detect[:encoding]) message.encode!("utf-8", detect[:encoding], undef: :replace, replace: "", invalid: :replace) end # ensure message encoding is utf8 message.valid_encoding? ? message : raise # Prevent app from crash cause of encoding errors rescue encoding = detect ? detect[:encoding] : "unknown" "--broken encoding: #{encoding}" end def detect_encoding message return nil unless message hash = CharlockHolmes::EncodingDetector.detect(message) rescue {} return hash[:encoding] ? hash[:encoding] : nil end end end
Проблема возникает в строке номер 21, помеченной комментарием: «Если сообщение не в UTF-8, конвертируем». Кодировка изначально была неверно определена в строке 14, поэтому дальше при попытке конвертации в UTF-8 происходит косяк.
Заменим в строках под номерами 22 и 23 выражение detect[:encoding]
на строку "windows-1251"
(вместе с кавычками), наглядно намекнув gitlab’у, что он не прав. Теперь этот блок должен выглядеть вот так:
# if message is not utf-8 encoding, convert it
if detect[:encoding]
message.force_encoding("windows-1251")
message.encode!("utf-8", "windows-1251", undef: :replace, replace: "", invalid: :replace)
end
Сохраняем. Перезапускаем демона:
sudo service gitlab restart
Всё, теперь наши комментарии на русском языке в файлах с кодировкой CP1251 будут отображаться в читабельном виде. Конец.
P.S. И да, это костыль, но он вполне допустим в нашем случае, когда сервером пользуется два человека, и код поставляется лишь в двух кодировках: UTF-8 и Windows-1251. Но это баг Чарлока Холмса, ждём апдейтов 🙂