Недавно я столкнулся с жестким диском и потерял весь исходный код. Можно ли загрузить/проверить код, который я уже загрузил в Google App Engine (например, самую последнюю версию)?
Можно ли восстановить исходный код, загруженный в Google AppEngine?
Ответ 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 файл для загрузки
Я мало знаю о движке или разрешениях приложения, но похоже, что это возможно.