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

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

问题描述

最近我有一个硬盘驱动器崩溃,丢失了所有的源代码。是否可以提取/结帐我已经上传到Google App Engine的代码(如最新版本)? 解决方案

因为我只是想尽办法解决如何做到这一点,所以我认为我可以将它作为答案包括在内,即使它不适用于您:

在继续之前,请在妈妈的坟墓上发誓,下次您将代码备份起来,或者更好地使用源代码管理。我的意思是:在我之后重复下一次我将使用源代码管理。好吧,完成之后,让我们看看是否有可能为您恢复您的代码...



如果您的应用是用Java编写的,恐怕您如果你的应用程序是用Python编写的,并且同时拥有 remote_api deferred 处理程序,可以通过这两个API的交互来恢复您的源代码。基本技巧如下:


  1. 启动remote_api_shell

  2. 创建一个新的延迟任务,并将它们写入数据存储区

  3. 等待该任务执行

  4. 使用remote_api从数据存储区中提取数据
  5. >

按顺序查看它们:

启动remote_api_shell



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

  remote_api_shell.py your_app_id 

如果shell不在您的路径中,请将该命令作为App Engine SDK目录路径的前缀。 p>

将源代码写入数据存储区

这里我们将利用延迟处理程序已安装,您可以使用remote_api为延迟排队任务,并且可以推迟调用Python内置函数'eval'。

Thi由于'eval'只执行单个语句而不是任意代码块,所以我们需要将整个代码作为单个语句来形成。这里是:

$ $ p $ $ $ $ $ $ $ $ $ $ $ $'$'$ $' $ b(__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()
用于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):传递

使用' import ''这里是另一个解决方法,我们不能使用语句:表达式 __ import __('google.appengine.ext.db')导入引用的模块,并返回由于 type()返回新类,所以我们现在有一个Expando模块(谷歌)。 我们可以使用子类将数据存储到数据存储区。接下来,我们调用它的构造函数,传递两个参数'name'和'data'。我们从当前处理的目录和文件连接构造的名称,而数据是打开该文件名并读取其内容的结果,包装在一个db.Text对象中,因此可以任意长。最后,我们在返回的实例上调用.put()以将其存储到数据存储中。



为了读取和存储所有源文件,这个表达式发生在列表理解中,它首先对 os的结果进行迭代。它能方便地返回基本目录下的所有目录和文件,然后返回每个目录中的每个文件。该表达式的返回值 - 写入数据存储区的密钥列表 - 仅由延迟模块丢弃。然而,这并不重要,因为它只是我们关心的副作用。

最后,我们称推迟函数为推迟eval的调用,表达式我们只是将其描述为它的参数。

读出数据



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

 从google.appengine.ext导入os 
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)同样不包含在内,并且无法恢复 - 您需要重新编写它们。尽管如此,比重写你的整个应用程序好多了,对吗?

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)?

解决方案

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...

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.

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. Start the remote_api_shell
  2. Create a new deferred task that reads in all your files and writes them to the datastore
  3. Wait for that task to execute
  4. Extract your data from the datastore, using remote_api

Looking at them in order:

Starting the remote_api_shell

Simply type the following from a command line:

remote_api_shell.py your_app_id

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

Writing your source to the datastore

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'.

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:

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

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).

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.

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.

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

Reading out the data

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.

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天全站免登陆