diff --git a/app/helpers/installation_helper.rb b/app/helpers/installation_helper.rb index 022fd0e5..1f4f36ad 100644 --- a/app/helpers/installation_helper.rb +++ b/app/helpers/installation_helper.rb @@ -1,8 +1,25 @@ # frozen_string_literal: true module InstallationHelper + # The block, plus a way out for the readers whose bootloader cannot run it. + # + # guarded_flash joins the transfer to the erase and the write with `&&` so a + # failed transfer cannot reach the erase -- see the comment on that method for + # the camera that cost. But `&&` is a hush feature, and stock vendor + # bootloaders are what people are running when they follow this page for the + # first time. At least one does not have it: the reporter in + # OpenIPC/firmware#2299 got "the help entry for the first command" back and + # had to enter each part by hand. + # + # That failure is safe -- nothing is transferred, nothing is erased -- but it + # is silent about why, and the line is not one a reader can take apart + # unaided. So say it, next to the block it applies to, and only there. def list_of_commands(text) - content_tag 'pre', text.join('
').html_safe, class: 'bg-light p-4' + block = content_tag 'pre', text.join('
').html_safe, class: 'bg-light p-4' + return block unless text.any? { |line| line.to_s.include?('&&') } + + safe_join([block, content_tag('p', t('firmware.installation.compound_caveat_html'), + class: 'small text-muted')]) end def do_not_copy_paste diff --git a/config/locales/de.yml b/config/locales/de.yml index 988c6af3..708e87ab 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -74,6 +74,7 @@ de: subtitle: Sichern Sie Ihre Standard-Firmware. Überspringen Sie diesen Teil des Installationsprozesses nicht! title: Speichern Sie die Original-Firmware backup_32: AUFMERKSAMKEIT! Stellen Sie vor dem Sichern von 32 MB Flash-ROM sicher, dass die Kamera über mindestens 64 MB RAM verfügt. + compound_caveat_html: Wenn der Bootloader einen Hinweis zur Verwendung ausgibt, statt die Zeile auszuführen, versteht er && nicht. Geben Sie die Teile einzeln ein und führen Sie jeden erst aus, nachdem der vorhergehende Erfolg gemeldet hat — genau diese Prüfung nimmt Ihnen && ab. flashing: alternative: Alternativ können Sie die OpenIPC-Firmware einzeln flashen flashing_footfs: diff --git a/config/locales/en.yml b/config/locales/en.yml index f665157f..b3b2414a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -74,6 +74,7 @@ en: subtitle: Back up your stock firmware, don't skip this part of the installation process! title: Save the original firmware backup_32: ATTENTION! Before backing up 32M flash ROM, make sure that the camera has at least 64M of RAM. + compound_caveat_html: If your bootloader answers with a usage message instead of running the line, it does not understand &&. Enter the parts one at a time, and run each one only after the part before it has reported success — that check is what && does for you. flashing: alternative: Alternatively, flash OpenIPC Firmware by its parts flashing_footfs: diff --git a/config/locales/es.yml b/config/locales/es.yml index a0cd5c05..72c23ae7 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -74,6 +74,7 @@ es: subtitle: Haga una copia de seguridad de su firmware original, ¡no se salte esta parte del proceso de instalación! title: Guarde el firmware original backup_32: "¡ATENCIÓN! Antes de realizar una copia de seguridad de la ROM flash de 32 M, asegúrese de que la cámara tenga al menos 64 M de RAM." + compound_caveat_html: Si el gestor de arranque responde con un mensaje de uso en lugar de ejecutar la línea, no entiende &&. Introduzca las partes de una en una y ejecute cada una solo después de que la anterior haya indicado que ha tenido éxito — esa comprobación es lo que && hace por usted. flashing: alternative: Alternativamente, actualice el firmware OpenIPC por sus partes flashing_footfs: diff --git a/config/locales/fa.yml b/config/locales/fa.yml index 785806cf..9232fcb5 100644 --- a/config/locales/fa.yml +++ b/config/locales/fa.yml @@ -74,6 +74,7 @@ fa: subtitle: از سیستم عامل استوک خود نسخه پشتیبان تهیه کنید، این قسمت از فرآیند نصب را نادیده نگیرید! title: سیستم عامل اصلی را ذخیره کنید backup_32: توجه! قبل از پشتیبان گیری از رام فلش 32M، مطمئن شوید که دوربین حداقل 64M رم دارد. + compound_caveat_html: اگر بوت‌لودر به‌جای اجرای این خط، راهنمای استفادهٔ فرمان را نمایش داد، یعنی && را نمی‌شناسد. بخش‌ها را یکی‌یکی وارد کنید و هر بخش را تنها پس از آنکه بخش پیشین موفقیت را گزارش کرد اجرا کنید — همین بررسی همان کاری است که && برای شما انجام می‌دهد. flashing: alternative: یا، فریمور OpenIPC را با قطعات آن فلش کنید flashing_footfs: diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 9870ef1c..5b4e9191 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -74,6 +74,7 @@ fr: subtitle: Sauvegardez votre firmware d'origine, ne sautez pas cette partie du processus d'installation ! title: Enregistrez le firmware d'origine backup_32: ATTENTION! Avant de sauvegarder une ROM flash de 32 Mo, assurez-vous que l'appareil photo dispose d'au moins 64 Mo de RAM. + compound_caveat_html: Si le chargeur d'amorçage affiche un message d'utilisation au lieu d'exécuter la ligne, c'est qu'il ne comprend pas &&. Saisissez les parties une par une et n'exécutez chacune qu'après que la précédente a signalé une réussite — c'est exactement la vérification que && effectue pour vous. flashing: alternative: Vous pouvez également flasher le micrologiciel OpenIPC par ses pièces. flashing_footfs: diff --git a/config/locales/it.yml b/config/locales/it.yml index 63f4cb10..6038beb8 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -74,6 +74,7 @@ it: subtitle: Esegui il backup del firmware di serie, non saltare questa parte del processo di installazione! title: Salvare il firmware originale backup_32: ATTENZIONE! Prima di eseguire il backup della ROM flash da 32 MB, assicurarsi che la fotocamera disponga di almeno 64 MB di RAM. + compound_caveat_html: Se il bootloader risponde con un messaggio d'uso invece di eseguire la riga, non riconosce &&. Inserire le parti una alla volta ed eseguire ciascuna solo dopo che la precedente ha riportato esito positivo — è proprio questo il controllo che && svolge per voi. flashing: alternative: In alternativa, eseguire il flashing del firmware OpenIPC dalle sue parti flashing_footfs: diff --git a/config/locales/pl.yml b/config/locales/pl.yml index ca9d90e6..291c15e9 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -74,6 +74,7 @@ pl: subtitle: Utwórz kopię zapasową oprogramowania sprzętowego, nie pomijaj tej części procesu instalacji! title: Zapisz oryginalne oprogramowanie sprzętowe backup_32: UWAGA! Przed utworzeniem kopii zapasowej pamięci flash ROM o pojemności 32 MB upewnij się, że aparat ma co najmniej 64 MB pamięci RAM. + compound_caveat_html: Jeśli bootloader zamiast wykonać wiersz wypisuje sposób użycia polecenia, nie rozumie &&. Wprowadzaj części pojedynczo i uruchamiaj każdą dopiero wtedy, gdy poprzednia zgłosi powodzenie — to właśnie tę kontrolę wykonuje za ciebie &&. flashing: alternative: Alternatywnie, flashuj oprogramowanie sprzętowe OpenIPC według jego części flashing_footfs: diff --git a/config/locales/pt.yml b/config/locales/pt.yml index c8062b44..91e77650 100644 --- a/config/locales/pt.yml +++ b/config/locales/pt.yml @@ -74,6 +74,7 @@ pt: subtitle: Faça backup do seu firmware padrão, não pule esta parte do processo de instalação! title: Salve o firmware original backup_32: ATENÇÃO! Antes de fazer backup de ROM flash de 32M, certifique-se de que a câmera tenha pelo menos 64M de RAM. + compound_caveat_html: Se o bootloader responder com uma mensagem de utilização em vez de executar a linha, não reconhece &&. Introduza as partes uma de cada vez e execute cada uma apenas depois de a anterior indicar sucesso — é essa verificação que && faz por si. flashing: alternative: Como alternativa, atualize o firmware OpenIPC por suas partes flashing_footfs: diff --git a/config/locales/ru.yml b/config/locales/ru.yml index d2a75f2f..84b7fde8 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -74,6 +74,7 @@ ru: subtitle: Сделайте резервную копию стоковой прошивки, не пропускайте эту часть процесса установки! title: Сохраните оригинальную прошивку backup_32: ВНИМАНИЕ! Перед резервным копированием 32-мегабайтной флэш-памяти убедитесь, что камера имеет не менее 64 МБ оперативной памяти. + compound_caveat_html: Если загрузчик в ответ печатает подсказку по использованию команды вместо того, чтобы выполнить строку, значит он не понимает &&. Вводите части по одной и запускайте каждую следующую только после того, как предыдущая сообщит об успехе — именно эту проверку и делает за вас &&. flashing: alternative: В качестве альтернативы прошивайте прошивку OpenIPC по частям. flashing_footfs: diff --git a/config/locales/zh.yml b/config/locales/zh.yml index beda5d2c..94a4d62d 100644 --- a/config/locales/zh.yml +++ b/config/locales/zh.yml @@ -74,6 +74,7 @@ zh: subtitle: 备份您的原始固件,请不要跳过这个步骤! title: 保存原始固件 backup_32: 请注意!在备份 32M 闪存之前,请确保摄像机至少有 64M 的 RAM。 + compound_caveat_html: 如果引导程序输出的是命令用法说明而不是执行该行,说明它不支持 &&。请逐条输入各个部分,并且每一条都要等前一条报告成功之后再执行——这正是 && 替你做的检查。 flashing: alternative: 或者,通过其烧录部分 OpenIPC 固件 flashing_footfs: diff --git a/test/controllers/socs_controller_test.rb b/test/controllers/socs_controller_test.rb index 9a91969d..105ff349 100644 --- a/test/controllers/socs_controller_test.rb +++ b/test/controllers/socs_controller_test.rb @@ -599,6 +599,35 @@ def submit_in_russian(soc, flash_type, firmware_version) end end + # --- the way out when the bootloader has no `&&` --- + + # guarded_flash joins the transfer to the erase with `&&` so a failed transfer + # cannot reach the erase. `&&` is a hush feature, and the bootloader people + # are running when they first follow this page is the stock vendor one -- the + # reporter in OpenIPC/firmware#2299 got "the help entry for the first command" + # back from theirs. Nothing is erased in that case, but nothing explains it + # either, so the block that uses `&&` says what to do instead. + test 'a block built with && carries the note about bootloaders that lack it' do + soc = instructable_soc('TS3516EVD00') + + with_release_index(*every_edition_for(soc)) do + submit(soc, 'nor8m') + + assert_match '&& sf erase', response.body + assert_match 'it does not understand &&', response.body + end + end + + test 'the note is translated, not another hardcoded English string' do + soc = instructable_soc('TS3516EVD10') + + with_release_index(*every_edition_for(soc)) do + I18n.with_locale(:ru) { submit(soc, 'nor8m') } + + assert_match 'не понимает &&', response.body + end + end + # --- the permanent link --- def permalink_for(**attrs) diff --git a/test/helpers/installation_helper_test.rb b/test/helpers/installation_helper_test.rb new file mode 100644 index 00000000..bf7c7426 --- /dev/null +++ b/test/helpers/installation_helper_test.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'test_helper' + +class InstallationHelperTest < ActionView::TestCase + include InstallationHelper + + # The note belongs to the blocks that chain with `&&` and to no others. A + # page carries several blocks and only some of them chain, so this is the + # level where the rule is visible; the controller test covers it end to end. + test 'a block that chains with && is followed by the note' do + html = list_of_commands(['tftpboot 0x82000000 f && sf erase 0x0 0x800000']) + + assert_includes html, 'it does not understand &&' + end + + # guarded_flash is `transfer && erase && write` -- two gates, not one. The + # first wording said to run the erase and the write once the transfer had + # succeeded, which rebuilds only the first gate: a reader whose erase failed + # would have gone on to write into flash that was never cleared. The rule has + # to be sequential to cover both, so pin that rather than the sentence. + test 'the note gates every part on the one before it, not just on the transfer' do + html = list_of_commands(['tftpboot 0x82000000 f && sf erase 0x0 0x800000 && sf write 0x82000000 0x0 0x1000']) + + assert_includes html, 'only after the part before it has reported success' + assert_not_includes html, 'after the transfer has reported success' + end + + # `run setnor8m`, `run uknand; run urnand`, the mw.b lines -- none of these + # chain, so the note would be answering a question the block has not raised. + test 'a block that does not chain is left alone' do + html = list_of_commands(['run setnor8m']) + + assert_equal '
run setnor8m
', html + end + + test 'the note is html, not escaped markup' do + html = list_of_commands(['tftp 0x82000000 f && sf erase 0x0 0x800000']) + + assert_includes html, '&&' + assert_not_includes html, '<code>' + end +end