Могу ли я восстановить исходный код, который был загружен в Google AppEngine? - PullRequest
16 голосов
/ 19 марта 2010

Недавно у меня сломался жесткий диск, и я потерял весь свой исходный код. Можно ли вытащить / извлечь код, который я уже загрузил в Google App Engine (например, самую последнюю версию)?

Ответы [ 7 ]

41 голосов
/ 21 марта 2010

Поскольку я только что решил выяснить, как это сделать, я полагаю, что с тем же успехом могу включить его в качестве ответа, даже если он к вам не относится:

Прежде чем продолжить, поклянись на могиле твоей матери, что в следующий раз ты будешь делать резервные копии своего кода или, что лучше, использовать систему контроля версий. Я имею в виду: повторите за мной " в следующий раз, когда я буду использовать контроль источника ". Хорошо, с этим покончено, давайте посмотрим, возможно ли восстановить ваш код для вас ...

Если ваше приложение написано на Java, боюсь, вам не повезло - исходный код даже не загружается в App Engine для приложений Java.

Если ваше приложение было написано на Python и для него определены обработчики remote_api и deferred , вы можете восстановить исходный код с помощью взаимодействия этих двух API. Основной трюк выглядит так:

  1. Запустить remote_api_shell
  2. Создайте новую отложенную задачу, которая читает все ваши файлы и записывает их в хранилище данных
  3. Дождаться выполнения этой задачи
  4. Извлеките ваши данные из хранилища данных, используя remote_api

Глядя на них по порядку:

Запуск remote_api_shell

Просто введите в командной строке следующее:

remote_api_shell.py your_app_id

Если в вашем пути нет оболочки, добавьте к команде префикс с путем к каталогу SDK App Engine.

Запись вашего источника в хранилище данных

Здесь мы собираемся воспользоваться тем фактом, что у вас установлен обработчик deferred, что вы можете использовать remote_api для постановки в очередь задач для deferred и что вы можете отложить вызов встроенной функции Python 'eval' .

Это немного усложняется тем фактом, что 'eval' выполняет только один оператор, а не произвольный блок кода, поэтому нам нужно сформулировать весь код как один оператор. Вот оно:

expr = """
[type(
    'CodeFile',
    (__import__('google.appengine.ext.db').appengine.ext.db.Expando,),
    {})(
        name=dp+'/'+fn,
        data=__import__('google.appengine.ext.db').appengine.ext.db.Text(
            open(dp + '/' + fn).read()
        )
    ).put()
 for dp, dns, fns in __import__('os').walk('.')
 for fn in fns]
"""

from google.appengine.ext.deferred import defer
defer(eval, expr)

Довольно взломать. Давайте посмотрим на это немного за раз:

Сначала мы используем встроенную функцию type для динамического создания нового подкласса db.Expando . Три аргумента type() - это имя нового класса, список родительских классов и переменная класса. Все первые 4 строки выражения эквивалентны этому:

from google.appengine.ext import db
class CodeFile(db.Expando): pass

Использование ' import ' здесь является еще одним обходным решением для того факта, что мы не можем использовать операторы: выражение __import__('google.appengine.ext.db') импортирует указанный модуль и возвращает модуль верхнего уровня (Google) .

Поскольку type() возвращает новый класс, теперь у нас есть подкласс Expando, который мы можем использовать для хранения данных в хранилище данных. Затем мы вызываем его конструктор, передавая ему два аргумента: «имя» и «данные». Имя, которое мы создаем из конкатенации каталога и файла, с которым мы сейчас имеем дело, в то время как данные являются результатом открытия этого имени файла и чтения его содержимого, обернутого в объект db.Text, поэтому оно может быть произвольно длинным. Наконец, мы вызываем .put () для возвращенного экземпляра, чтобы сохранить его в хранилище данных.

Чтобы прочитать и сохранить весь исходный код, а не только один файл, все это выражение помещается в понимание списка, которое сначала перебирает результат os.walk , который удобно возвращает все каталоги и файлы в базовом каталоге, а затем поверх каждого файла в каждом из этих каталогов. Возвращаемое значение этого выражения - список ключей, которые были записаны в хранилище данных - просто отбрасывается отложенным модулем. Это не имеет значения, так как нас интересуют только побочные эффекты.

Наконец, мы вызываем функцию defer, откладывающую вызов eval, с выражением, которое мы только что описали в качестве аргумента.

Считывание данных

После выполнения описанного выше и ожидания его завершения мы можем извлечь данные из хранилища данных, снова используя remote_api. Во-первых, нам нужна локальная версия модели кода файла:

import os
from google.appengine.ext import db
class CodeFile(db.Model):
  name = db.StringProperty(required=True)
  data = db.TextProperty(required=True)

Теперь мы можем извлечь все его сущности, сохранив их на диске:

for cf in CodeFile.all():
  os.makedirs(os.dirname(cf.name))
  fh = open(cf.name, "w")
  fh.write(cf.data)
  fh.close()

Вот и все! Ваша локальная файловая система должна теперь содержать ваш исходный код.

Одно предупреждение: скачанный код будет содержать только ваш код и файлы данных. Статические файлы не включены, хотя вы должны иметь возможность просто загрузить их по HTTP, если вы помните, что они все. Файлы конфигурации, такие как app.yaml, также не включены и не могут быть восстановлены - вам нужно их переписать. Тем не менее, это намного лучше, чем переписывать все приложение, верно?

32 голосов
/ 06 декабря 2010

Обновление: Google appengine теперь позволяет загружать код (для приложений Python, Java, PHP и Go)

Инструмент Документация здесь .

4 голосов
/ 19 марта 2010

К сожалению, ответ - нет. Это общий вопрос о SO и платах движка приложения. См. здесь и здесь , например.

Я уверен, что с вами все будет в порядке, потому что вы сохраняете весь свой код в системе контроля версий, верно? ;)

Если вы хотите, чтобы это было вариантом в будущем, вы можете загрузить zip-архив вашего src со ссылкой на него где-то в вашем веб-приложении, как часть процесса сборки / развертывания.

Существуют также проекты, подобные , этот , которые автоматизируют этот процесс для вас.

3 голосов
/ 06 июля 2016

Обнаружено, что вы можете запустить следующее в своей консоли (командная строка / терминал). Просто убедитесь, что appcfg.py доступен через ваш $ PATH.

locate appcfg.py

По умолчанию приведенный ниже код распечатывает каждый файл и процесс загрузки.

appcfg.py download_app -A APP_ID -V VERSION_ID ~/Downloads
2 голосов
/ 06 декабря 2012

Вы МОЖЕТЕ получить свой код, даже на Java. Это просто требует немного реинжиниринга. Вы можете скачать файл war, используя appengine SDK, выполнив следующие инструкции: https://developers.google.com/appengine/docs/java/tools/uploadinganapp

Тогда у вас по крайней мере есть файлы классов, которые вы можете запустить через JAD, чтобы вернуться к исходным файлам (по крайней мере, близко к нему).

0 голосов
/ 09 марта 2018

Вы должны вернуться к более раннему sdk, appcfg.py не в последнем sdk Вид боли, но это работает. Это должно быть гораздо более заметным в литературе. Мне стоил целый день.

0 голосов
/ 19 марта 2010

если вы используете python ... вы можете написать скрипт, который откроет все файлы в его текущем и дочерних каталогах и добавит их в zip-файл для загрузки

Я не знаю много о движке приложения или разрешениях, но кажется, что это возможно

...