12 марта в 17:32

Как спасти потерянный исходный код на Python, если он все еще не выгружен из памяти tutorial recovery mode

Это перевод вчерашней заметки от Simon Willison

Я облажался, бездумно используя git (git checkout -- — не на том файле) и умудрился удалить код, который я только что написал… но он все еще был загружен в исполняемый процесс в докер-контейнере. Вот, как я восстановил код, используя https://pypi.python.org/pypi/pyrasite/ и https://pypi.python.org/pypi/uncompyle6


Подключите удаленный шелл к докеру


Установите GDB (это требует pyrasite)


apt-get update && apt-get install gdb

Установите pyrasite — это позволит подключить питоновкий шелл к запущенному процессу


pip install pyrasite

Установите uncompyle6, это позволит декомпилировать объекты в памяти обратно в питоновский код


pip install uncompyle6

Отыщите PID процесса, который исполняет ваш код


ps aux | grep python

Подключите интерактивный шелл используя pyrasite


pyrasite-shell <PID>

Итак, у нас есть интерактивный питоновский шелл! Импортируйте код, который необходимо восстановить


>>> from my_package import my_module

Определите, какие функции и классы мы восстанавливаем


>>> dir(my_module)
['MyClass', 'my_function']

Декомпилируйте функции в исходный код


>>> import uncompyle6
>>> import sys
>>> uncompyle6.main.uncompyle(
    2.7, my_module.my_function.func_code, sys.stdout
)
# uncompyle6 version 2.9.10
# Python bytecode 2.7
# Decompiled from: Python 2.7.12 (default, Nov 19 2016, 06:48:10) 
# [GCC 5.4.0 20160609]
# Embedded file name: /srv/my_package/my_module.py
function_body = "appears here"

Для классов, придется декомпилировать каждый метод по отдельности


>>> uncompyle6.main.uncompyle(
    2.7, my_module.MyClass.my_method.im_func.func_code, sys.stdout
)
# uncompyle6 version 2.9.10
# Python bytecode 2.7
# Decompiled from: Python 2.7.12 (default, Nov 19 2016, 06:48:10) 
# [GCC 5.4.0 20160609]
# Embedded file name: /srv/my_package/my_module.py
class_method_body = "appears here"

Вот он, ваш было почти утерянный код.

Ида Лифшиц @am-amotion-city
карма
–16,0
рейтинг 37,5
Стратег
Самое читаемое Разработка

Комментарии (28)

  • –24

    Проще положить исходники в dropbox. Хотя конечно, если дропбокс не успел синхронизировать файлы — придётся изворачиваться именно так. Да и CPU и fs дропбокс нагружает очень не слабо, если много папок.

  • +1
    А разве нельзя взять *.pyc файлы и декомпилировать те которые вам нужны?
    • +2

      Можно, конечно, если они есть. Там в самом начале описан юзкейс и я в него попадал сам: мне показалось, что пошаговая инструкция заслуживает того, чтобы попасть в закладки.

  • +15
    На git надейся, да сам не плошай — тут-то и спасёт локальная история изменений в IDE.
  • +13
    Вывод — комитьте чаще.
    • +6

      Это, кстати, абсолютная истина: я взял за привычку коммитить чуть ли не каждый чих. Учитывая, насколько просто потом все причесать с git rebase, это — единственно верная стратегия вообще.

      • 0
        А как причесать?
      • 0
        я взял за привычку коммитить чуть ли не каждый чих.

        +1


        причесать с git rebase

        Ну если полная история всех тех чихов изменений не нужна есть же commit --amend (сразу) или тот же "быстрый squash" (не знаю как по-русски его зовут):
        git reset --soft HEAD~3 && git commit — сошьет 3-и последних коммита в один.


        Если взять за привычку всегда работать в ветке work, то ее можно сливать (в тот же master) опять же одним коммитом:
        git checkout master && git merge --squash work && git commit ...
        Или чтоб остаться в ветке work:
        git reset --soft master && git commit ...


        Да много еще как можно...


        Тогда и git rebase нужен будет только чтобы ветки кидать туда сюда (для чего он собственно и делался)...

        • 0
          git reset --soft HEAD~3 && git commit

          Зачем это, когда есть --fixup?


          1.7.4.txt: * "git commit" learned --fixup and --squash options to help later invocation
          1.7.4.txt-   of the interactive rebase.

          . vvzvlad ⇑ вот вам замечательно ответили.

          • 0
            Зачем это, когда есть --fixup

            Чем оно проще?
            Строго говоря fixup это (несколько странный* имхо) хелпер для git rebase -i --autostash --autosquash...


            Мне не нравится как минимум полное собрание всех месседжей от всех interim коммитов.
            Во вторых если я не хочу "интерактивно" (а это как правило так, ибо нужно тупо смять все в одно)?
            Ну и в третьих кто вам мешает оформить ваш любимый способ squash тоже как какой-нить алиас. ;)


            * теперь почему он странный: ну вот я привык работать в ветке w, имеем там 3-и interim коммита (относительно мастер ветки).
            Хочу слить все три сквашем до master и остаться в ветке w.
            Интуитивно я бы вызвал это как-нибудь так: git commit --fixup master или git commit --squash master (и все).
            А имеем то что имеем...


            Поэтому есть собственный алиас sq2 (aka squashto) который делает то что выше описал…
            git sq2 master
            или даже сложнее — слить только 2-а первых коммита и оставить последний отдельным…
            git sq2 master..w~1

            • 0

              Ну, может быть :)


              Вопрос привычки. Я не делаю squash в рабочих ветках вообще, поэтому и не очень в теме.

  • +4
    Еще случай — если код был открыт в каком-нибудь пайчарме, то он скорее всего еще есть в его кэше, и его оттуда можно сравнительно легко вытащить

    Разумеется, эта фишка есть не только в пайчарме, а, скорее всего, во всех джетбрейнсовских редакторах
    • +6

      Local history действительно есть во всех джетбрейнсовских IDE. Но ведь автор пользуется вимом. Для него есть как минимум два плагина истории. Шах и мат, Джетбрейнс!

    • 0

      В неазслуженно регулярно забываемом Eclipse тоже есть. Меня однажды спасло, когда сделал git reset --hard не в том каталоге.

  • +9
    Вообще любой файл, который еще не был закрыт, можно спасти:
    root@test:~# lsof 123
    COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
    python  3193 root    3r   REG  252,1       15 1476 123
    root@test:~# cat 123
    Test test test
    root@test:~# rm -f 123
    root@test:~# cat 123
    cat: 123: No such file or directory
    root@test:~# ll /proc/3193/fd/
    total 0
    dr-x------ 2 root root  0 Mar 12 19:56 ./
    dr-xr-xr-x 9 root root  0 Mar 12 19:56 ../
    lrwx------ 1 root root 64 Mar 12 19:56 0 -> /dev/pts/10
    lrwx------ 1 root root 64 Mar 12 19:56 1 -> /dev/pts/10
    lrwx------ 1 root root 64 Mar 12 19:56 2 -> /dev/pts/10
    lr-x------ 1 root root 64 Mar 12 19:56 3 -> /root/123 (deleted)
    root@test:~# cat /proc/3193/fd/3
    Test test test
    root@test:~# cat /proc/3193/fd/3 > 456
    root@test:~# cat 456
    Test test test
    
    • +1
      Я заметку оригинального автора понял так что файл не удалён(разлинкован) был, а его контент был переписан контентом файла из репы и что единственное место в котором хранились данные из файла до перезаписи была память процесса в контейнере.

      А вот про айноды, хардлинки и что на самом деле «трёт rm» — это да, знать, ИМХО, должен каждый себя уважающий Линуксоид.
  • –2
    Установите…
    ...Ubuntu.
    Без apt-get в тексте не обойтись никак?
    • +2

      Во-первых, убунту тут ни при чем. Этот дистрибутив — лишь один из многих, унаследовавших apt как систему управления пакетами.


      Во-вторых, я убежден, что в заметках такого типа (в отличие от руководства по написанию ToDo блокнота на очередном хипстерском движке) нелепо оговариваться насчет «apt-get — это установщик пакетов». Если человек вдруг про это не в курсе, ему лучше не дочитывать заметку до конца, целее будет.

      • –6
        Ой ли? Не собираюсь ввязываться в холивары, но.
        Но еще тринадцать лет назад я не подозревал, что
        унаследовавших apt как систему управления пакетами

        Никак не хотел оскорбить!

        Пусть! Пусть будет(у жены установлена бубунта)!
        Тезисом не надо навязывать — это имел ввиду.
        • +5

          Я не смог распарсить ваш русский язык, видимо мой парсер грамматики нуждается в корректировке, но уловил нотки сомнения в моих словах.


          Даже Вика (sic!) знает, где и как родился apt (там можно сходить по ссылке Ubuntu и почитать, на базе какого дистрибутива один небезызвестный южноафриканец решил делать свой, почему, да как).

          • 0
            Ха, «минусы» после вашего комментария!
  • 0
    В некотором смысле извращение, наверное, но любую инфу, которая побывала на экране (в т. ч. то, что не писалось в файлы, типа просранного коммента), можно восстановить, если держать постоянно включенной программу, делающую снимки экрана раз в n секунд (TimeSnapper под винду, или вот, вроде, кроссплатформенное).
    • –1
      Ну позвольте! Я же не сказал(зачем оправдываюсь?)

      В целом, ситуация обстоит так(ИМХО): Если вы не умеете пользоваться «установщиком» вашей системы — статья НЕ для вас.
  • –3
    >Я облажался,
    облажался трижды:
    — бездумно использовал гит
    — не умеет пользоваться своей IDE/редактором (history)
    — не умеет пользоваться дропбоксом
    • +4

      Ну, гуру, которые никогда не ошибаются с гитом, мы, простые смертные, только завидуем.


      Дропбоксом вменяемые люди для кода под NDA не пользуются никогда. В компаниях, которые послеживают за новостями в IT, dropbox на рабочем месте запрещен в принципе.


      Вы не поняли, про что заметка, но это не страшно.

      • 0
        Не понял про гуру гита, вы про кого? А также не увидел букв NDA в заметке. По каким признакам вы решили, что у автора код под NDA и дропбокс плохая идея? Кстати, про пункт использования IDE вы тактично умолчали почему-то )

        UPDATE: как бонус 600k невменяемых результатов из гугла https://www.google.ru/search?q=use%20dropbox%20as%20code%20repository
  • 0
    Я бы всё же сначала бы дамп памяти сделал бы, а то одно неловкое движение завершит отлаживаемый процесс и адиос.
    • 0

      Ну да, ну да :)


      Перевод же ж.


      Я лично на шифт-принтскрин дамп памяти давно замаппил.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.