我可以恢复已上传到 Google AppEngine 的源代码吗? [英] Can I restore my source code that has been uploaded into Google AppEngine?

查看:27
本文介绍了我可以恢复已上传到 Google AppEngine 的源代码吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近有一个硬盘驱动器崩溃并丢失了我的所有源代码.是否可以提取/签出我已上传到 Google App Engine 的代码(如最新版本)?

I recently had a hard drive crashed and lost all of my source code. Is it possible to pull/checkout the code that I have already uploaded to Google App Engine (like the most recent version)?

推荐答案

由于我刚刚费尽心思弄清楚如何做到这一点,我想我也可以将其作为答案包含在内,即使它没有"t 适用于您:

Since I just went to all the trouble of figuring out how to do this, I figure I may as well include it as an answer, even if it doesn't apply to you:

在继续之前,在你母亲的坟墓上发誓下次你会备份你的代码,或者更好的是,使用源代码控制.我的意思是:在我之后重复下次我将使用源代码管理".好的,完成后,让我们看看是否可以为您恢复您的代码...

Before continuing, swear on your mother's grave that next time you will back your code up, or better, use source control. I mean it: Repeat after me "next time I will use source control". Okay, with that done, let's see if it's possible to recover your code for you...

如果您的应用是用 Java 编写的,恐怕您就不走运了 - 对于 Java 应用,源代码甚至没有上传到 App Engine.

If your app was written in Java, I'm afraid you're out of luck - the source code isn't even uploaded to App Engine, for Java apps.

如果您的应用是用 Python 编写的,并且同时具有 remote_apideferred 处理程序定义,可以通过这两者的交互来恢复您的源代码蜜蜂.基本技巧是这样的:

If your app was written in Python, and had both the remote_api and deferred handlers defined, it's possible to recover your source code through the interaction of these two APIs. The basic trick goes like this:

  1. 启动 remote_api_shell
  2. 创建一个新的延迟任务,读取您的所有文件并将它们写入数据存储区
  3. 等待任务执行
  4. 使用 remote_api 从数据存储中提取数据

按顺序查看:

只需从命令行输入以下内容:

Simply type the following from a command line:

remote_api_shell.py your_app_id

如果 shell 不在您的路径中,请在命令前面加上 App Engine SDK 目录的路径.

If the shell isn't in your path, prefix the command with the path to the App Engine SDK directory.

在这里,我们将利用以下事实:您安装了延迟处理程序,您可以使用 remote_api 将任务排入延迟队列,并且您可以延迟调用 Python 内置函数eval".

Here we're going to take advantage of the fact that you have the deferred handler installed, that you can use remote_api to enqueue tasks for deferred, and that you can defer an invocation of the Python built-in function 'eval'.

由于 'eval' 只执行一条语句,而不是任意的代码块,所以这有点棘手,因此我们需要将整个代码表述为一条语句.这是:

This is made slightly trickier by the fact that 'eval' executes only a single statement, not an arbitrary block of code, so we need to formulate our entire code as a single statement. Here it is:

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)

相当的黑客.让我们一次看一下:

Quite the hack. Let's look at it a bit at a time:

首先,我们使用'type'内置函数动态创建db.Expando.type() 的三个参数是新类的名称、父类的列表和类变量的字典.整个表达式的前 4 行等价于:

First, we use the 'type' builtin function to dynamically create a new subclass of db.Expando. The three arguments to type() are the name of the new class, the list of parent classes, and the dict of class variables. The entire first 4 lines of the expression are equivalent to this:

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

此处使用import"是我们无法使用语句这一事实的另一种解决方法:表达式 __import__('google.appengine.ext.db') 导入引用的模块,并返回顶级模块 (google).

The use of 'import' here is another workaround for the fact that we can't use statements: The expression __import__('google.appengine.ext.db') imports the referenced module, and returns the top-level module (google).

由于 type() 返回新类,我们现在有一个可用于将数据存储到数据存储的 Expando 子类.接下来,我们调用它的构造函数,向它传递两个参数,name"和data".我们从当前正在处理的目录和文件的串联中构造的名称,而数据是打开该文件名并读取其内容的结果,包装在 db.Text 对象中,因此它可以是任意长的.最后,我们对返回的实例调用 .put() 以将其存储到数据存储区.

Since type() returns the new class, we now have an Expando subclass we can use to store data to the datastore. Next, we call its constructor, passing it two arguments, 'name' and 'data'. The name we construct from the concatenation of the directory and file we're currently dealing with, while the data is the result of opening that filename and reading its content, wrapped in a db.Text object so it can be arbitrarily long. Finally, we call .put() on the returned instance to store it to the datastore.

为了读取和存储所有源代码,而不是一个文件,整个表达式发生在列表推导式中,该推导式首先对 os.walk,它方便地返回基本目录下的所有目录和文件,然后覆盖每个目录中的每个文件.该表达式的返回值 - 写入数据存储的键列表 - 被延迟模块简单地丢弃.不过,这并不重要,因为我们关心的只是副作用.

In order to read and store all the source, instead of just one file, this whole expression takes place inside a list comprehension, which iterates first over the result of os.walk, which conveniently returns all the directories and files under a base directory, then over each file in each of those directories. The return value of this expression - a list of keys that were written to the datastore - is simply discarded by the deferred module. That doesn't matter, though, since it's only the side-effects we care about.

最后,我们调用 defer 函数,推迟对 eval 的调用,并将我们刚刚描述的表达式作为其参数.

Finally, we call the defer function, deferring an invocation of eval, with the expression we just described as its argument.

执行完上述操作并等待它完成后,我们可以再次使用 remote_api 从数据存储中提取数据.首先,我们需要一个本地版本的代码文件模型:

After executing the above, and waiting for it to complete, we can extract the data from the datastore, again using remote_api. First, we need a local version of the codefile model:

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

现在,我们可以获取它的所有实体,并将它们存储到磁盘:

Now, we can fetch all its entities, storing them to disk:

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

就是这样!您的本地文件系统现在应该包含您的源代码.

That's it! Your local filesystem should now contain your source code.

一个警告:下载的代码将只包含您的代码和数据文件.静态文件不包括在内,但您应该能够简单地通过 HTTP 下载它们,如果您还记得它们都是什么的话.配置文件(例如 app.yaml)同样不包含在内,并且无法恢复 - 您需要重写它们.不过,总比重写整个应用要好得多,对吧?

One caveat: The downloaded code will only contain your code and datafiles. Static files aren't included, though you should be able to simply download them over HTTP, if you remember what they all are. Configuration files, such as app.yaml, are similarly not included, and can't be recovered - you'll need to rewrite them. Still, a lot better than rewriting your whole app, right?

这篇关于我可以恢复已上传到 Google AppEngine 的源代码吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆