import os import json import svn.local import werkzeug import xml.etree.ElementTree import logging from multiprocessing import Process from flask import Flask from flask import jsonify from flask import abort from flask import request from flask import make_response from flask import url_for from flask import Response from flask.ext.restful import Api from flask.ext.restful import Resource from flask.ext.restful import reqparse from flask.ext.restful import fields from flask.ext.restful import marshal from application import auth from application import app from application import log from application import db from application.modules.admin import backend from application.modules.admin import settings from application.modules.projects import admin from application.modules.projects.model import Project from application.modules.projects.model import ProjectSetting from application.modules.resources.model import Bundle class DirectoryAPI(Resource): """Displays list of files.""" decorators = [auth.login_required] def __init__(self): parser = reqparse.RequestParser() # parser.add_argument('rate', type=int, help='Rate cannot be converted') parser.add_argument('path', type=str) # args = parser.parse_args() super(DirectoryAPI, self).__init__() def get(self, project_name): project = Project.query.filter_by(name=project_name).first() path = request.args['path'] if not path: path = '' path_root_abs = project.repository_path parent_path = '' if path != '': path_root_abs = os.path.join(path_root_abs, path) parent_path = os.pardir if not os.path.isdir(path_root_abs): return jsonify(message="Path is not a directory %r" % path_root_abs) items_list = [] for f in os.listdir(path_root_abs): # ignore svn internal paths if f == ".svn": continue f_rel = os.path.join(path, f) f_abs = os.path.join(path_root_abs, f) if os.path.isdir(f_abs): items_list.append((f, f_rel, "dir")) else: items_list.append((f, f_rel, "file")) project_files = { "parent_path": parent_path, "items_list": items_list, } return jsonify(project_files) # return {'message': 'Display files list'} class FileAPI(Resource): """Gives acces to a file. Currently requires 2 arguments: - filepath: the path of the file (relative to the project root) - the command (info, checkout) In the case of checkout we plan to support the following arguments: --dependencies --zip (eventually with a compression rate) Default behavior for file checkout is to retunr a zipfile with all dependencies. """ decorators = [auth.login_required] def __init__(self): parser = reqparse.RequestParser() parser.add_argument('filepath', type=str, help="Filepath cannot be blank!") parser.add_argument('command', type=str, required=True, help="Command cannot be blank!") parser.add_argument('arguments', type=str) parser.add_argument('files', type=werkzeug.datastructures.FileStorage, location='files') # args = parser.parse_args() super(FileAPI, self).__init__() def get(self, project_name): command = request.args['command'] command_args = request.args.get('arguments') if command_args is not None: command_args = json.loads(command_args) project = Project.query.filter_by(name=project_name).first() if command == 'info': filepath = request.args['filepath'] r = svn.local.LocalClient(project.repository_path) svn_log = r.log_default(None, None, 5, filepath) svn_log = [l for l in svn_log] size = os.path.getsize(os.path.join(r.path, filepath)) # Check bundle_status: (ready, in_progress) full_filepath = os.path.join(project.repository_path, filepath) b = Bundle.query.filter_by(source_file_path=full_filepath).first() if b: bundle_status = b.status else: bundle_status = None return jsonify( filepath=filepath, log=svn_log, size=size, bundle_status=bundle_status) elif command == 'bundle': filepath = request.args['filepath'] #return jsonify(filepath=filepath, status="building") filepath = os.path.join(project.repository_path, filepath) if not os.path.exists(filepath): return jsonify(message="Path not found %r" % filepath) elif os.path.isdir(filepath): return jsonify(message="Path is a directory %r" % filepath) def bundle(): def report(txt): pass # pack the file! import tempfile # weak! (ignore original opened file) filepath_zip = tempfile.mkstemp(dir=app.config['STORAGE_BUNDLES'], suffix=".zip") os.close(filepath_zip[0]) filepath_zip = filepath_zip[1] # subprocess here for r in self.pack_fn( filepath, filepath_zip, project.repository_path, True, report, 'ZIP', ): pass b = Bundle.query.filter_by(source_file_path=filepath).first() if b: b.bundle_path = filepath_zip else: b = Bundle( source_file_path=filepath, bundle_path=filepath_zip) db.session.add(b) b.status = "available" db.session.commit() # once done, we update the queue, as well as the status of the # bundle in the table and serve the bundle_path # return jsonify(filepath=filepath_zip) # Check in database if file has been requested already b = Bundle.query.filter_by(source_file_path=filepath).first() if b: if b.status == "available": # Check if archive is available on the filesystem if os.path.isfile(b.bundle_path): # serve the local path for the zip file return jsonify(filepath=b.bundle_path, status="available") else: b.status = "building" db.session.commit() # build the bundle again elif b.status == "building": # we are waiting for the server to build the archive filepath=None return jsonify(filepath=filepath, status="building") # If file not avaliable, start the bundling and return a None filepath, # which the cloud will interpret as, no file is available at the moment p = Process(target=bundle,) p.start() filepath=None return jsonify(filepath=filepath, status="building") elif command == 'checkout': filepath = request.args['filepath'] filepath = os.path.join(project.repository_path, filepath) if not os.path.exists(filepath): return jsonify(message="Path not found %r" % filepath) elif os.path.isdir(filepath): return jsonify(message="Path is a directory %r" % filepath) def response_message_iter(): ID_MESSAGE = 1 ID_PAYLOAD = 2 import struct def report(txt): txt_bytes = txt.encode('utf-8') return struct.pack('= 0) yield struct.pack('