Google app engine 我可以恢复上传到Google AppEngine的源代码吗?
我最近有一个硬盘死机,丢失了所有的源代码。是否可以提取/签出我已经上传到Google App Engine(如最新版本)的代码?不幸的是,答案是否定的。这是SO和App Engine板上常见的问题。 参见和,例如 我相信你会没事的,因为你把所有的代码都保存在源代码管理中,对吗?;) 如果您希望将来可以选择此选项,您可以在构建/部署过程中上载src的zip,并在web应用程序中的某个位置添加指向它的链接Google app engine 我可以恢复上传到Google AppEngine的源代码吗?,google-app-engine,version-control,backup,Google App Engine,Version Control,Backup,我最近有一个硬盘死机,丢失了所有的源代码。是否可以提取/签出我已经上传到Google App Engine(如最新版本)的代码?不幸的是,答案是否定的。这是SO和App Engine板上常见的问题。 参见和,例如 我相信你会没事的,因为你把所有的代码都保存在源代码管理中,对吗?;) 如果您希望将来可以选择此选项,您可以在构建/部署过程中上载src的zip,并在web应用程序中的某个位置添加指向它的链接 也有类似的项目可以为您自动执行该过程。如果您使用python。。。您可以编写一个脚本,打开当前
也有类似的项目可以为您自动执行该过程。如果您使用python。。。您可以编写一个脚本,打开当前目录和子目录中的所有文件,并将它们添加到zipfile中供您下载
我对AppEngine或权限了解不多,但这似乎是可能的,因为我刚刚费尽心思想了想如何做到这一点,我想我也可以把它作为一个答案,即使它不适用于你: 在继续之前,向你母亲的坟墓发誓,下次你将备份你的代码,或者更好,使用源代码管理。我是认真的:在我后面重复“下次我将使用源代码管理”。好的,完成后,让我们看看是否有可能为您恢复代码 如果你的应用程序是用Java编写的,恐怕你运气不好——Java应用程序的源代码甚至没有上传到AppEngine 如果您的应用程序是用Python编写的,并且定义了和处理程序,则可以通过这两个API的交互来恢复源代码。基本技巧如下:
remote_api_shell.py your_app_id
如果shell不在您的路径中,请在命令前面加上appenginesdk目录的路径
将源代码写入数据存储
在这里,我们将利用这样一个事实:您已经安装了延迟处理程序,您可以使用远程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)
真是太棒了。让我们一次看一看:
首先,我们使用“type”内置函数动态创建的新子类。type()
的三个参数是新类的名称、父类列表和类变量的dict。表达式的前4行与此等效:
from google.appengine.ext import db
class CodeFile(db.Expando): pass
“import”的使用为解决我们不能使用语句的问题,这里有另一个解决方法:表达式\uuuuuuu import\uuuu('google.appengine.ext.db')
导入引用的模块,并返回顶级模块(google)
由于type()
返回新类,我们现在有了一个Expando子类,可以用来将数据存储到数据存储中。接下来,我们调用它的构造函数,向它传递两个参数“name”和“data”。我们从当前正在处理的目录和文件的连接中构造的名称,而数据是打开该文件名并读取其内容的结果,包装在db.Text对象中,因此可以任意长。最后,我们对返回的实例调用.put(),将其存储到数据存储中
为了读取和存储所有源文件,而不是一个文件,整个表达式发生在列表理解中,它首先迭代的结果,然后方便地返回基本目录下的所有目录和文件,然后遍历每个目录中的每个文件。这个表达式的返回值(写入数据存储的键列表)被延迟模块简单地丢弃。不过这并不重要,因为这只是我们关心的副作用
最后,我们调用defer函数,推迟eval的调用,将刚才描述的表达式作为其参数
读出数据
在执行上述操作并等待其完成后,我们可以再次使用远程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)也不包括在内,无法恢复-您需要重写它们。不过,这比重写整个应用程序要好得多,对吧?更新:谷歌appengine现在允许您下载代码(用于Python、Java、PHP和Go应用程序)
工具。即使在Java中,您也可以获取代码。它只需要一点逆向工程。您可以按照以下说明使用appengine SDK下载war文件:
然后,您至少有可以通过JAD运行的类文件,以返回到源文件(至少靠近源文件)。发现您可以在控制台(命令行/终端)中运行以下命令。只要确保appcfg.py可以通过$PATH访问即可
locate appcfg.py
默认情况下,下面的代码打印出每个文件和下载进度
appcfg.py download_app -A APP_ID -V VERSION_ID ~/Downloads
您必须恢复到以前的sdk,
/images/some_site_image.png
<path_to_cloud_install_dir>/google-cloud-sdk/platform/google_appengine/google/appengine/tools/appcfg.py
full_path = os.path.join(out_dir, path)
path = re.sub(r'^/', '', path)
google-cloud-sdk/platform/google_appengine/appcfg.py download_app -A <app> -V <version> 20200813t184800 <your_directory>