Commit 06aaf14a authored by Alain Takoudjou's avatar Alain Takoudjou

Merge branch 'slaprunner'

parents 0d97260a e97599ea
......@@ -111,17 +111,21 @@ def run():
def serve(config):
from views import app
workdir = os.path.join(config.runner_workdir, 'project')
software_link = os.path.join(config.runner_workdir, 'softwareLink')
app.config.update(**config.__dict__)
app.config.update(
software_log=config.software_root.rstrip('/') + '.log',
instance_log=config.instance_root.rstrip('/') + '.log',
workspace = workdir,
software_link=software_link,
instance_profile='instance.cfg',
software_profile='software.cfg',
SECRET_KEY="123456",
SECRET_KEY=os.urandom(24),
PERMANENT_SESSION_LIFETIME=timedelta(days=31),
)
if not os.path.exists(workdir):
os.mkdir(workdir)
if not os.path.exists(software_link):
os.mkdir(software_link)
app.run(host=config.runner_host, port=int(config.runner_port),
debug=config.debug, threaded=True)
# -*- coding: utf-8 -*-
import os
import urllib
from flask import jsonify
from werkzeug import secure_filename
import shutil
import datetime
import hashlib
from utils import realpath, tail, isText
import re
import zipfile
class fileBrowser(object):
"""This class contain all bases function for file browser"""
def __init__(self, config):
self.config = config
def listDirs(self, dir, all=False):
"""List elements of directory 'dir' taken"""
html = ''
html += 'var gsdirs = new Array();'
html += 'var gsfiles = new Array();'
dir = urllib.unquote(str(dir))
realdir = realpath(self.config, dir)
if not realdir:
raise NameError('Could not load directory %s: Permission denied' % dir)
ldir = sorted(os.listdir(realdir), key=str.lower)
for f in ldir:
if f.startswith('.') and not all: #do not display this file/folder
continue
ff = os.path.join(dir,f)
realfile = os.path.join(realdir, f)
mdate = datetime.datetime.fromtimestamp(os.path.getmtime(realfile)
).strftime("%Y-%d-%m %I:%M")
md5 = hashlib.md5(realfile).hexdigest()
if not os.path.isdir(realfile):
size = os.path.getsize(realfile)
regex = re.compile("(^.*)\.(.*)", re.VERBOSE)
ext = regex.sub(r'\2', f)
if ext == f:
ext = "unknow"
else:
ext = str.lower(ext)
html += 'gsfiles.push(new gsItem("1", "' + f + '", "' + \
ff + '", "' + str(size) + '", "' + md5 + \
'", "' + ext + '", "' + mdate + '"));';
else:
html += 'gsdirs.push(new gsItem("2", "' + f + '", "' + \
ff + '", "0", "' + md5 + '", "dir", "' + mdate + '"));';
return html
def makeDirectory(self, dir, filename):
"""Create a directory"""
realdir = realpath(self.config, urllib.unquote(dir))
if not realdir:
raise NameError('Could not load directory %s: Permission denied' % dir)
folder = os.path.join(realdir, filename)
if not os.path.exists(folder):
os.mkdir(folder, 0744)
return '{result: \'1\'}'
else:
return '{result: \'0\'}'
def makeFile(self, dir, filename):
"""Create a file in a directory dir taken"""
realdir = realpath(self.config, urllib.unquote(dir))
if not realdir:
raise NameError('Could not load directory %s: Permission denied' % dir)
file = os.path.join(realdir, filename)
if not os.path.exists(file):
open(file, 'w').write('')
return 'var responce = {result: \'1\'}'
else:
return '{result: \'0\'}'
def deleteItem(self, dir, files):
"""Delete a list of files or directories"""
realdir = realpath(self.config, urllib.unquote(dir))
if not realdir:
raise NameError('Could not load directory %s: Permission denied' % dir)
lfiles = urllib.unquote(files).split(',,,')
try:
for file in lfiles:
file = os.path.join(realdir, file)
if not os.path.exists(file):
continue #silent skip file....
details = file.split('/')
last = details[len(details) - 1]
if last and last.startswith('.'):
continue #cannot delete this file/directory, to prevent security
if os.path.isdir(file):
shutil.rmtree(file)
else:
os.unlink(file)
except Exception, e:
return str(e)
return '{result: \'1\'}'
def copyItem(self, dir, files, del_source=False):
"""Copy a list of files or directory to dir"""
realdir = realpath(self.config, urllib.unquote(dir))
if not realdir:
raise NameError('Could not load directory %s: Permission denied' % dir)
lfiles = urllib.unquote(files).split(',,,')
try:
for file in lfiles:
realfile = realpath(self.config, file)
if not realfile:
raise NameError('Could not load file or directory %s: Permission denied' % file)
#prepare destination file
details = realfile.split('/')
dest = os.path.join(realdir, details[len(details) - 1])
if os.path.exists(dest):
raise NameError('NOT ALLOWED OPERATION : File or directory already exist')
if os.path.isdir(realfile):
shutil.copytree(realfile, dest)
if del_source:
shutil.rmtree(realfile)
else:
shutil.copy(realfile, dest)
if del_source:
os.unlink(realfile)
except Exception, e:
return str(e)
return '{result: \'1\'}'
def rename(self, dir, filename, newfilename):
"""Rename file or directory to dir/filename"""
realdir = realpath(self.config, urllib.unquote(dir))
if not realdir:
raise NameError('Could not load directory %s: Permission denied' % dir)
realfile = realpath(self.config, urllib.unquote(filename))
if not realfile:
raise NameError('Could not load directory %s: Permission denied' % filename)
tofile = os.path.join(realdir, newfilename)
if not os.path.exists(tofile):
os.rename(realfile, tofile)
return '{result: \'1\'}'
raise NameError('NOT ALLOWED OPERATION : File or directory already exist')
def copyAsFile(self, dir, filename, newfilename):
"""Copy file or directory to dir/filename"""
realdir = realpath(self.config, urllib.unquote(dir))
if not realdir:
raise NameError('Could not load directory %s: Permission denied' % dir)
fromfile = os.path.join(realdir, filename)
tofile = os.path.join(realdir, newfilename)
if not os.path.exists(fromfile):
raise NameError('NOT ALLOWED OPERATION : File or directory not exist')
if not os.path.exists(tofile):
shutil.copy(fromfile, tofile)
return '{result: \'1\'}'
raise NameError('NOT ALLOWED OPERATION : File or directory already exist')
def uploadFile(self, dir, files):
"""Upload a list of file in directory dir"""
realdir = realpath(self.config, urllib.unquote(dir))
if not realdir:
raise NameError('Could not load directory %s: Permission denied' % dir)
for file in files:
if files[file]:
filename = secure_filename(files[file].filename)
if not os.path.exists(os.path.join(dir, filename)):
files[file].save(os.path.join(realdir, filename))
return '{result: \'1\'}'
def downloadFile(self, dir, filename):
"""Download file dir/filename"""
realdir = realpath(self.config, urllib.unquote(dir))
if not realdir:
raise NameError('Could not load directory %s: Permission denied' % dir)
file = os.path.join(realdir, urllib.unquote(filename))
if not os.path.exists(file):
raise NameError('NOT ALLOWED OPERATION : File or directory does not exist %s'
% os.path.join(dir, filename))
return file
def zipFile(self, dir, filename, newfilename):
"""Add filename to archive as newfilename"""
realdir = realpath(self.config, urllib.unquote(dir))
if not realdir:
raise NameError('Could not load directory %s: Permission denied' % dir)
tozip = os.path.join(realdir, newfilename)
fromzip = os.path.join(realdir, filename)
if not os.path.exists(fromzip):
raise NameError('NOT ALLOWED OPERATION : File or directory not exist')
if not os.path.exists(tozip):
zip = zipfile.ZipFile(tozip, 'w', zipfile.ZIP_DEFLATED)
if os.path.isdir(fromzip):
rootlen = len(fromzip) + 1
for base, dirs, files in os.walk(fromzip):
for file in files:
fn = os.path.join(base, file).encode("utf-8")
zip.write(fn, fn[rootlen:])
else:
zip.write(fromzip)
zip.close()
return '{result: \'1\'}'
raise NameError('NOT ALLOWED OPERATION : File or directory already exist')
def unzipFile(self, dir, filename, newfilename):
"""Extract a zipped archive"""
realdir = realpath(self.config, urllib.unquote(dir))
if not realdir:
raise NameError('Could not load directory %s: Permission denied' % dir)
target = os.path.join(realdir, newfilename)
archive = os.path.join(realdir, filename)
if not os.path.exists(archive):
raise NameError('NOT ALLOWED OPERATION : File or directory not exist')
if not os.path.exists(target):
zip = zipfile.ZipFile(archive)
#member = zip.namelist()
zip.extractall(target)
#if len(member) > 1:
# zip.extractall(target)
#else:
# zip.extract(member[0], newfilename)
return '{result: \'1\'}'
raise NameError('NOT ALLOWED OPERATION : File or directory already exist')
def readFile(self, dir, filename, truncate=0):
"""Read file dir/filename and return content"""
realfile = realpath(self.config, os.path.join(urllib.unquote(dir),
urllib.unquote(filename)))
if not realfile:
raise NameError('Could not load directory %s: Permission denied' % dir)
if not isText(realfile):
return "FILE ERROR: Cannot display binary file, please open a text file only!"
if truncate == 0:
return open(realfile, 'r').read()
else:
tail(open(realfile, 'r'), 0)
UL.jqueryFileTree {
font-family: Verdana, sans-serif;
font-size: 12px;
line-height: 18px;
padding: 0px;
margin: 0px;
}
UL.jqueryFileTree LI {
list-style: none;
padding: 0px;
padding-left: 20px;
margin: 0px;
white-space: nowrap;
}
UL.jqueryFileTree A {
color: #333;
text-decoration: none;
}
UL.jqueryFileTree A:hover {
background: #BDF;
}
.gs_dir_list{display: none;}
.gs_dir_content {
height: 100%;
width: 100%;
}
.gs_dir_content_menu {
padding: 0 0 0 5px;
margin-bottom: 5px;
border: 1px solid #BBBBBB;
background-color: white;
}
.gs_dir_content_button {
background: url("data:image/gif;base64,R0lGODlhKAAVAJEAAPn5+e7u7uPj4////yH5BAEAAAMALAAAAAAoABUAAAIxhI+py+0Po5y02ouz3rz7FoTiSJbmiabqGgruC8fyTNf2jef6zvf+DwwKh8Si8SgsAAA7") repeat-x scroll 0 0 transparent;
border: 1px outset #BBBBBB;
cursor: pointer;
margin-right: 7px;
font-weight: bold;
padding: 1px;
background-position: 0, 50;
text-decoration: none;
color: black;
}
.gs_dir_content_button:hover {
color: #EF7929;
border: 1px inset #BBBBBB;
}
.gs_dir_content_files {
min-height: 250px;
max-height: 400px;
overflow: auto;
background-color: white;
border: 1px solid #BBBBBB;
}
#curDir {
height: 30px;
line-height: 30px;
}
#gsClipBoard{display: none;}
.directory_info {
padding-left: 20px;
}
.directory_info a {
text-decoration: none;
}
#rootLink {
display: none;
}
.loadingDiv {
width: 100%;
height: 75px;
margin-top: 50px;
background: url(images/loading.gif) center center no-repeat;
}
.demoto {
width: 100%;
height: 100%;
}
.dir_index {
cursor: pointer;
}
.toggleplus {
background: url('images/toggle_plus.png') left top no-repeat;
}
.toggleminus {
background: url('images/toggle_minus.png') left top no-repeat;
}
.dirs_files_table {
width: 100%;
font-size: 12px;
}
.dirs_files_table td{padding: 0;border:none}
.gsItem {padding: 4px; padding-left: 25px;}
.file_ext_name {
font-weight: normal;
color: #FF6600;
}
.gsHeadTable {
width :100%;
}
.dirs_files_table tr:hover {background: #BDF;}
.gsHeadText {
color:#666;
height:34px;
font-weight: bold;
}
.gs_head{padding: 10px 5px 10px 0;}
.gs_title{padding-left: 10px; margin:5px 5px 0 0; background: #e4e4e4;}
.rowSelected {
color: #FFF;
background-color: #c2c2c2;
}
.rowSelected a {
color: #FFF;
}
.gs_delimiter {
height: 16px;
line-height: 16px;
}
/* Core Styles */
.directory {
background-image:url(images/directory.png);
background-repeat:no-repeat;
}
.directoryMeny a { background: url(images/directory.png) left top no-repeat; padding-left: 20px}
/*.jqueryFileTree LI.expanded { background: url(images/folder_open.png) 20px top no-repeat; }*/
.file {
background-image:url(images/file.png);
background-repeat:no-repeat;
cursor:pointer;
}
.jqueryFileTree LI.wait { background: url(images/spinner.gif) left top no-repeat; }
/* File Extensions*/
.ext_3gp {
background-image: url(images/film.png) left top no-repeat;
}
.ext_afp {
background-image: url(images/code.png); }
.ext_afpa {
background-image: url(images/code.png); }
.ext_asp {
background-image: url(images/code.png); }
.ext_aspx {
background-image: url(images/code.png); }
.ext_avi {
background-image: url(images/film.png); }
.ext_bat {
background-image: url(images/application.png); }
.ext_bmp {
background-image: url(images/picture.png); }
.ext_c {
background-image: url(images/code.png); }
.ext_cfm {
background-image: url(images/code.png); }
.ext_cgi {
background-image: url(images/code.png); }
.ext_com {
background-image: url(images/application.png); }
.ext_cpp {
background-image: url(images/code.png); }
.ext_css {
background-image: url(images/css.png); }
.ext_doc {
background-image: url(images/doc.png); }
.ext_exe {
background-image: url(images/application.png); }
.ext_gif {
background-image: url(images/picture.png);
}
.ext_fla {
background-image: url(images/flash.png); }
.ext_h {
background-image: url(images/code.png); }
.ext_htm {
background-image: url(images/html.png); }
.ext_html {
background-image: url(images/html.png); }
.ext_jar {
background-image: url(images/java.png); }
.ext_jpg {
background-image: url(images/picture.png);
}
.ext_jpeg {
background-image: url(images/picture.png); }
.ext_js {
background-image: url(images/script.png) ; }
.ext_lasso {
background-image: url(images/code.png) ; }
.ext_log {
background-image: url(images/txt.png) ; }
.ext_m4p {
background-image: url(images/music.png); }
.ext_mov {
background-image: url(images/film.png); }
.ext_mp3 {
background-image: url(images/music.png); }
.ext_mp4 {
background-image: url(images/film.png); }
.ext_mpg {
background-image: url(images/film.png); }
.ext_mpeg {
background-image: url(images/film.png); }
.ext_ogg {
background-image: url(images/music.png); }
.ext_pcx {
background-image: url(images/picture.png); }
.ext_pdf {
background-image: url(images/pdf.png); }
.ext_php {
background-image: url(images/php.png); }
.ext_png {
background-image: url(images/picture.png); }
.ext_ppt {
background-image: url(images/ppt.png); }
.ext_psd {
background-image: url(images/psd.png); }
.ext_pl {
background-image: url(images/script.png);; }
.ext_py {
background-image: url(images/script.png) ;}
.ext_rb {
background-image: url(images/ruby.png); }
.ext_rbx {
background-image: url(images/ruby.png); }
.ext_rhtml {
background-image: url(images/ruby.png); }
.ext_rpm {
background-image: url(images/linux.png); }
.ext_ruby {
background-image: url(images/ruby.png); }
.ext_sql {
background-image: url(images/db.png); }
.ext_swf {
background-image: url(images/flash.png); }
.ext_tif {
background-image: url(images/picture.png); }
.ext_tiff {
background-image: url(images/picture.png); }
.ext_txt {
background-image: url(images/txt.png) ; }
.ext_vb {
background-image: url(images/code.png) ; }
.ext_wav {
background-image: url(images/music.png) ; }
.ext_wmv {
background-image: url(images/film.png); }
.ext_xls {
background-image: url(images/xls.png) ; }
.ext_xml {
background-image: url(images/code.png) ; }
.ext_zip {
background-image: url(images/zip.png) ; }
.ext_cfg {
background-image: url(images/cfg.png) ; }
/* Generic context menu styles */
.contextMenu {
position: absolute;
width: 160px;
z-index: 99999;
border: solid 1px #CCC;
background: #EEE;
padding: 0px;
margin: 0px;
display: none;
}
.contextMenu LI {
list-style: none;
padding: 0px;
margin: 0px;
}
.contextMenu A {
color: #333;
text-decoration: none;
display: block;
line-height: 20px;
height: 20px;
background-position: 6px center;
background-repeat: no-repeat;
outline: none;
padding: 1px 5px;
padding-left: 28px;
}
.contextMenu LI.hover A {
color: #FFF;
background-color: #3399FF;
}
.contextMenu LI.disabled A {
color: #AAA;
cursor: default;
}
.contextMenu LI.hover.disabled A {
background-color: transparent;
}
.contextMenu LI.separator {
border-top: solid 1px #CCC;
}
/*
Adding Icons
You can add icons to the context menu by adding
classes to the respective LI element(s)
*/
.contextMenu LI.edit A { background-image: url(images/page_white_edit.png); }
.contextMenu LI.cut A { background-image: url(images/cut.png); }
.contextMenu LI.copy A { background-image: url(images/page_white_copy.png); }
.contextMenu LI.paste A { background-image: url(images/page_white_paste.png); }
.contextMenu LI.delete A { background-image: url(images/cross.png); }
.contextMenu LI.quit A { background-image: url(images/door.png); }
.contextMenu LI.directorymenu A { background-image: url(images/folder_open.png); }
.contextMenu LI.rename A { background-image: url(images/mfile.png); }
.contextMenu LI.download A { background-image: url(images/disk.png); }
.contextMenu LI.notepad A { background-image: url(images/page_white_edit.png); }
.contextMenu LI.picture A { background-image: url(images/mpicture.png); }
.contextMenu LI.newfile A { background-image: url(images/new_file.png); }
.contextMenu LI.newdir A { background-image: url(images/new_dir.png); }
.contextMenu LI.uploadfolder A { background-image: url(images/upload_folder.png); }
.contextMenu LI.selection A { background-image: url(images/selection-select.png); }
.contextMenu LI.zip A { background-image: url(images/mzip.png); }
\ No newline at end of file
slapos/runner/static/css/images/cfg.png

764 Bytes | W: | H:

slapos/runner/static/css/images/cfg.png

756 Bytes | W: | H:

slapos/runner/static/css/images/cfg.png
slapos/runner/static/css/images/cfg.png
slapos/runner/static/css/images/cfg.png
slapos/runner/static/css/images/cfg.png
  • 2-up
  • Swipe
  • Onion skin
slapos/runner/static/css/images/code.png

603 Bytes | W: | H:

slapos/runner/static/css/images/code.png

655 Bytes | W: | H:

slapos/runner/static/css/images/code.png
slapos/runner/static/css/images/code.png
slapos/runner/static/css/images/code.png
slapos/runner/static/css/images/code.png
  • 2-up
  • Swipe
  • Onion skin
slapos/runner/static/css/images/css.png

618 Bytes | W: | H:

slapos/runner/static/css/images/css.png

674 Bytes | W: | H:

slapos/runner/static/css/images/css.png
slapos/runner/static/css/images/css.png
slapos/runner/static/css/images/css.png
slapos/runner/static/css/images/css.png
  • 2-up
  • Swipe
  • Onion skin
slapos/runner/static/css/images/db.png

579 Bytes | W: | H:

slapos/runner/static/css/images/db.png

635 Bytes | W: | H:

slapos/runner/static/css/images/db.png
slapos/runner/static/css/images/db.png
slapos/runner/static/css/images/db.png
slapos/runner/static/css/images/db.png
  • 2-up
  • Swipe
  • Onion skin
slapos/runner/static/css/images/directory.png

427 Bytes | W: | H:

slapos/runner/static/css/images/directory.png

459 Bytes | W: | H:

slapos/runner/static/css/images/directory.png
slapos/runner/static/css/images/directory.png
slapos/runner/static/css/images/directory.png
slapos/runner/static/css/images/directory.png
  • 2-up
  • Swipe
  • Onion skin
slapos/runner/static/css/images/doc.png

651 Bytes | W: | H:

slapos/runner/static/css/images/doc.png

743 Bytes | W: | H:

slapos/runner/static/css/images/doc.png
slapos/runner/static/css/images/doc.png
slapos/runner/static/css/images/doc.png
slapos/runner/static/css/images/doc.png
  • 2-up
  • Swipe
  • Onion skin
slapos/runner/static/css/images/file.png

294 Bytes | W: | H:

slapos/runner/static/css/images/file.png

425 Bytes | W: | H:

slapos/runner/static/css/images/file.png
slapos/runner/static/css/images/file.png
slapos/runner/static/css/images/file.png
slapos/runner/static/css/images/file.png
  • 2-up
  • Swipe
  • Onion skin
slapos/runner/static/css/images/film.png

653 Bytes | W: | H:

slapos/runner/static/css/images/film.png

767 Bytes | W: | H:

slapos/runner/static/css/images/film.png
slapos/runner/static/css/images/film.png
slapos/runner/static/css/images/film.png
slapos/runner/static/css/images/film.png
  • 2-up
  • Swipe
  • Onion skin
slapos/runner/static/css/images/flash.png

582 Bytes | W: | H:

slapos/runner/static/css/images/flash.png

630 Bytes | W: | H:

slapos/runner/static/css/images/flash.png
slapos/runner/static/css/images/flash.png
slapos/runner/static/css/images/flash.png
slapos/runner/static/css/images/flash.png
  • 2-up
  • Swipe
  • Onion skin
slapos/runner/static/css/images/html.png

734 Bytes | W: | H:

slapos/runner/static/css/images/html.png

791 Bytes | W: | H:

slapos/runner/static/css/images/html.png
slapos/runner/static/css/images/html.png
slapos/runner/static/css/images/html.png
slapos/runner/static/css/images/html.png
  • 2-up
  • Swipe
  • Onion skin
slapos/runner/static/css/images/java.png

633 Bytes | W: | H:

slapos/runner/static/css/images/java.png

417 Bytes | W: | H:

slapos/runner/static/css/images/java.png
slapos/runner/static/css/images/java.png
slapos/runner/static/css/images/java.png
slapos/runner/static/css/images/java.png
  • 2-up
  • Swipe
  • Onion skin
slapos/runner/static/css/images/linux.png

668 Bytes | W: | H:

slapos/runner/static/css/images/linux.png

720 Bytes | W: | H:

slapos/runner/static/css/images/linux.png
slapos/runner/static/css/images/linux.png
slapos/runner/static/css/images/linux.png
slapos/runner/static/css/images/linux.png
  • 2-up
  • Swipe
  • Onion skin