2010-03-19 9 views
16

Hace poco tuve un disco duro bloqueado y perdí todo mi código fuente. ¿Es posible extraer/verificar el código que ya he cargado en Google App Engine (como la versión más reciente)?¿Puedo restablecer mi código fuente que se ha subido a Google AppEngine?

+2

Disculpa por tu disco duro. Para proyectos futuros, pruebe algo como Github o Bitbucket de forma gratuita (siempre que lo mantenga de código abierto) y una forma fácil de mantener una copia remota de su código fuente. – bernie

+0

Gracias por la sugerencia, pero eso es que no puedo usar esos porque lo que estoy haciendo no va a ser de código abierto. – chustar

+0

Puede obtener una cuenta de alojamiento web básica que incluye control de fuente (subversión) por $ 5 al mes. Yo uso geekisp.com pero estoy seguro de que hay muchos otros, tal vez algunos son incluso más baratos por solo svn. –

Respuesta

41

Como me tomé la molestia de encontrar la manera de hacerlo, me parece que puedo incluirlo como una respuesta, incluso si no se aplica a usted:

Antes de continuar, jure por la tumba de su madre que la próxima vez respaldará su código arriba, o mejor, use el control de fuente. Lo digo en serio: repite después de mí "la próxima vez usaré el control fuente". De acuerdo, con eso listo, veamos si es posible recuperar el código para usted ...

Si su aplicación fue escrita en Java, me temo que no tiene suerte - el código fuente no es par cargado en App Engine, para aplicaciones Java.

Si su aplicación fue escrita en Python y tenía los manejadores remote_api y deferred definidos, es posible recuperar su código fuente mediante la interacción de estas dos API. El truco básico es el siguiente:

  1. Iniciar el remote_api_shell
  2. crear una nueva tarea diferida que lee en todos los archivos y los graba en el almacén de datos
  3. Espere a que la tarea de ejecutar
  4. extraer sus datos del almacén de datos, utilizando remote_api

Mirándolos en orden:

de inicio ing del remote_api_shell

Simplemente escriba lo siguiente desde una línea de comandos:

remote_api_shell.py your_app_id 

Si la envoltura no se encuentra en su camino, como prefijo del comando con la ruta de acceso al directorio de SDK de App Engine.

Escribir su origen en el almacén de datos

Aquí vamos a aprovechar el hecho de que tiene instalado el controlador diferido, que se puede utilizar para encolar remote_api tareas para diferida, y que puede aplazar una invocación de la función incorporada de Python 'eval'.

Esto se hace un poco más complicado por el hecho de que 'eval' ejecuta solo una declaración, no un bloque arbitrario de código, por lo que tenemos que formular todo nuestro código como una declaración única. Aquí está:

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. Veámoslo un poco a la vez:

Primero, utilizamos la función incorporada 'tipo' para crear dinámicamente una nueva subclase de db.Expando. Los tres argumentos a type() son el nombre de la nueva clase, la lista de clases principales y el dict de las variables de clase. Los primeros enteros 4 líneas de la expresión son equivalentes a esto:

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

El uso de 'importación' aquí es otra solución para el hecho de que no podemos utilizar declaraciones: La expresión __import__('google.appengine.ext.db') importa el módulo referenciado y devuelve el módulo de nivel superior (google).

Dado que type() devuelve la nueva clase, ahora tenemos una subclase Expando que podemos usar para almacenar datos en el almacén de datos. A continuación, llamamos a su constructor, pasándole dos argumentos, 'nombre' y 'datos'. El nombre que construimos a partir de la concatenación del directorio y archivo con el que estamos trabajando actualmente, mientras que los datos son el resultado de abrir ese nombre de archivo y leer su contenido, envuelto en un objeto db.Text para que pueda ser arbitrariamente largo. Finalmente, llamamos a .put() en la instancia devuelta para almacenarla en el almacén de datos.

Para leer y almacenar toda la fuente, en lugar de solo un archivo, toda esta expresión tiene lugar dentro de una lista de comprensión, que itera primero sobre el resultado de os.walk, que devuelve convenientemente todos los directorios y archivos bajo una base directorio, luego sobre cada archivo en cada uno de esos directorios. El valor devuelto de esta expresión, una lista de claves que se escribieron en el almacén de datos, simplemente se descarta por el módulo diferido. Sin embargo, eso no importa, ya que son solo los efectos secundarios que nos importan.

Finalmente, llamamos a la función defer, difiriendo una invocación de eval, con la expresión que acabamos de describir como su argumento.

lectura de los datos

Después de ejecutar lo anterior, y esperar a que se complete, podemos extraer los datos del almacén de datos, utilizando de nuevo remote_api. En primer lugar, necesitamos una versión local del modelo CodeFile:

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

Ahora, podemos obtener todos sus entidades, almacenarlos en el disco:

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

Eso es todo! Su sistema de archivos local ahora debe contener su código fuente.

Una advertencia: El código descargado solo incluirá su código y sus archivos de datos. Los archivos estáticos no están incluidos, aunque debería poder descargarlos simplemente a través de HTTP, si recuerda cuáles son. Archivos de configuración, como la aplicación.yaml, de manera similar, no están incluidos, y no se pueden recuperar; tendrás que volver a escribirlos. Aún así, mucho mejor que reescribir toda tu aplicación, ¿verdad?

+8

Wow ............ –

+0

Gracias por esto. Sin embargo, mi aplicación fue escrita en Java. Estoy seguro de que al salir de la naturaleza de estilo wiki de stackoverflow, esto ayudará a alguien más que hizo lo mismo. – chustar

+0

Gracias por esto. –

4

Lamentablemente, la respuesta es no. Esta es una pregunta común en SO y en los tableros de motores de aplicaciones. Véase here y here por ejemplo.

Estoy seguro de que estarás bien, porque mantienes todo tu código en control de fuente, ¿verdad? ;)

Si desea que esto sea una opción en el futuro, puede cargar un archivo zip de su src, con un enlace a él en algún lugar de su aplicación web, como parte de su proceso de compilación/implementación.

También hay proyectos por ahí como this one que automatizan ese proceso para usted.

+0

+1 para la idea del archivo comprimido - es bueno tenerlo incluso si utilizo el control fuente –

0

si estás usando Python ... usted podría ser capaz de escribir un script que abre todos los archivos en el mismo directorio y de los niños actuales directorios y los añade a un archivo zip para descargar

I don' Sé mucho sobre el motor de la aplicación o los permisos, pero parece que eso podría ser posible.

+1

estoy seguro del 95% de que no funcionará en appengine, porque implementará su nueva secuencia de comandos "zipstuff" en un nuevo sistema de archivos "virtual" . –

+0

Definitivamente no funcionará como se describe. Creo que podría llevarlo a cabo si ya tiene los manejadores diferidos y remote_api registrados, usando un método ligeramente diferente. –

31

Actualización: Google appengine ahora le permite descargar el código (para Python, Java, PHP y aplicaciones Go)

herramienta documentation here.

+4

Realmente buenas noticias. Esta respuesta debe ser elegida. – DocWiki

+1

Sí, claro, excepto que ahora solo proporciona un código de error 404, por lo que quizás ahora sea mejor no haberlo elegido. Sin redirección No nada. ¿Cuánto podría cambiar la pregunta "¿Cómo descargo? ¿Por qué y sigo perdiendo el tiempo en este proyecto horriblemente documentado? – DanPride

+0

@DanPride También estoy teniendo problemas, ¿alguna vez tuvo una solución? – jdmdevdotnet

2

PUEDE obtener su código, incluso en Java. Solo requiere un poco de ingeniería inversa. Puede descargar el archivo war utilizando el appengine SDK siguiendo estas instrucciones: https://developers.google.com/appengine/docs/java/tools/uploadinganapp

Luego, al menos tiene los archivos de clase que puede ejecutar a través de JAD para volver a los archivos fuente (al menos, al menos).

2

Encontró que puede ejecutar lo siguiente en su consola (línea de comando/terminal). Solo asegúrese de que appcfg.py sea accesible a través de su $ PATH.

locate appcfg.py 

Por defecto, el siguiente código imprime cada archivo y el progreso de la descarga.

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

Si bien el código a menudo habla por sí mismo, las respuestas que solo contienen código y no tienen explicación textual, se marcan para las colas de revisión. Puede evitar esto agregando una o dos oraciones de explicación. – Will

+0

Gracias. No es frecuente que alguien lo pregunte muy bien. Editado como tal. Tomó nota para futuras referencias. –

+0

No hay problema, se ve genial :) Siempre dejo un comentario y marco como "Se ve bien" en las colas de revisión. Las explicaciones pueden ser realmente útiles para las personas que necesitan algún contexto o desean aprender más sobre lo que está sucediendo, y también ayudan a las personas a llegar desde los motores de búsqueda. – Will

0

Tienes que volver al sdk anterior, appcfg.py no está en el último sdk. Una especie de dolor, pero funciona. Debería ser mucho más prominente en la literatura. Me costó un día entero.

Cuestiones relacionadas