Подтвердить что ты не робот

Можно ли восстановить исходный код, загруженный в Google AppEngine?

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

4b9b3361

Ответ 1

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

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

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

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

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

Посмотрите на них в порядке:

Запуск remote_api_shell

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

remote_api_shell.py your_app_id

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

Написание источника в хранилище данных

Здесь мы воспользуемся тем фактом, что у вас установлен отложенный обработчик, который вы можете использовать remote_api для установки задач для отложенных задач и чтобы вы могли отложить вызов встроенной функции 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)

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

Сначала мы используем встроенную функцию типа, чтобы динамически создавать новый подкласс db.Expando. Три аргумента для type() - это имя нового класса, список родительских классов и dict переменных класса. Все первые 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, который удобно возвращает все каталоги и файлы в базовом каталоге, а затем по каждому файлу в каждом из этих каталогов. Возвращаемое значение этого выражения - список ключей, которые были записаны в хранилище данных, - просто отбрасывается отложенным модулем. Это не имеет значения, так как это только побочные эффекты, о которых мы заботимся.

Наконец, мы называем функцию отсрочки, откладывая вызов 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, также не включены и не могут быть восстановлены - вам нужно будет их переписать. Тем не менее, намного лучше, чем переписывать все ваше приложение, верно?

Ответ 2

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

Инструмент здесь.

Ответ 3

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

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

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

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

Ответ 4

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

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

Ответ 5

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

locate appcfg.py

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

appcfg.py download_app -A APP_ID -V VERSION_ID ~/Downloads

Ответ 6

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

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