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
slapos/runner/static/css/images/music.png

385 Bytes | W: | H:

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

691 Bytes | W: | H:

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

591 Bytes | W: | H:

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

639 Bytes | W: | H:

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

538 Bytes | W: | H:

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

591 Bytes | W: | H:

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

606 Bytes | W: | H:

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

715 Bytes | W: | H:

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

588 Bytes | W: | H:

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

661 Bytes | W: | H:

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

856 Bytes | W: | H:

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

918 Bytes | W: | H:

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

626 Bytes | W: | H:

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

676 Bytes | W: | H:

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

859 Bytes | W: | H:

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

955 Bytes | W: | H:

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

342 Bytes | W: | H:

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

529 Bytes | W: | H:

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

663 Bytes | W: | H:

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

714 Bytes | W: | H:

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

386 Bytes | W: | H:

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

590 Bytes | W: | H:

slapos/runner/static/css/images/zip.png
slapos/runner/static/css/images/zip.png
slapos/runner/static/css/images/zip.png
slapos/runner/static/css/images/zip.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -9,7 +9,7 @@ UL.jqueryFileTree {
UL.jqueryFileTree LI {
list-style: none;
padding: 0px;
padding-left: 22px;
padding-left: 25px;
margin: 0px;
white-space: nowrap;
}
......
#tabContaier{
background: #e4e4e4;
padding:3px;
position:relative;
/*position:relative;*/
width:757px;
font-size: 14px;
border-radius: 4px 4px 0 0;
......
......@@ -243,12 +243,12 @@ overflow-y: scroll;
color: #4c6172;
text-shadow: 0px 1px 1px #fff;
}
.dsblebutton{color:#9C9C9C; padding: 5px 10px;display: inline;background: #eee;
font-weight: bold; border:1px solid #000; margin-top:10px;}
.button {
padding: 5px 10px;
display: inline;
background: #eee;
border: none;
color: #000;
cursor: pointer;
font-weight: bold;
......
This diff is collapsed.
This diff is collapsed.
......@@ -3,7 +3,7 @@ $(document).ready(function(){
var hashes = window.location.href.split('#');
var fromheight = 0;
var previoustab = null;
if (hashes.length == 2 && hashes[1] != ""){
if (hashes.length == 2 && hashes[1] !== ''){
$("#tabContaier>ul li").each(function() {
var $tab = $(this).find("a");
if($tab.hasClass("active")){
......@@ -20,7 +20,7 @@ $(document).ready(function(){
else{$(".tabContents:first").show(); previoustab = ".tabContents:first";} // Show the first div of tab content by default
$("#tabContaier ul li a").click(function(){ //Fire the click event
if($(this).hasClass('active')){
return;
return false;
}
fromheight = $(previoustab).height();
var activeTab = $(this).attr("href"); // Catch the click link
......@@ -38,5 +38,6 @@ $(document).ready(function(){
});}
previoustab = activeTab;
$("#tabContaier .tabDetails").css("height", $("#tabContaier .tabDetails").height());
return false;//this reinitialize tab index when reload page
});
});
\ No newline at end of file
......@@ -3,15 +3,14 @@ String.prototype.toHtmlChar = function(){
var c = {'<':'&lt;', '>':'&gt;', '&':'&amp;', '"':'&quot;', "'":'&#039;',
'#':'&#035;' };
return this.replace( /[<&>'"#]/g, function(s) { return c[s]; } );
}
};
String.prototype.trim = function () {
return this.replace(/^\s*/, "").replace(/\s*$/, "");
}
};
/****************************************/
function setInput($elt) {
if(!$elt){var $elt = $('input[type="text"], input[type="password"]');}
if(!$elt){$elt = $('input[type="text"], input[type="password"]');}
$elt.addClass("idleField");
$elt.focus(function() {
$(this).removeClass("idleField").addClass("focusField");
......@@ -24,12 +23,28 @@ function setInput($elt) {
});
$elt.blur(function() {
$(this).removeClass("focusField").addClass("idleField");
if ($.trim(this.value) == ''){
if ($.trim(this.value) === ''){
this.value = (this.defaultValue ? this.defaultValue : '');
}
});
}
/*******************Bind remove all button*******************/
function bindRemove(){
$("a#removeSr").click(function(){
if(!window.confirm("Do you really want to remove all software release?")){
return false;
}
location.href = $SCRIPT_ROOT + '/removeSoftware';
});
$("a#removeIst").click(function(){
if(!window.confirm("Do you really want to remove all computer partition?")){
return false;
}
location.href = $SCRIPT_ROOT + '/removeInstance';
});
}
/**************************/
(function ($, document, window) {
$.extend($.fn, {
......
$(document).ready( function() {
var send = false;
var cloneRequest;
$('#fileTree').fileTree({ root: $("input#workdir").val(), script: $SCRIPT_ROOT + '/readFolder', folderEvent: 'click', expandSpeed: 750, collapseSpeed: 750, multiFolder: false }, function(file) {
selectFile(file);
});
$('#fileNavigator').gsFileManager({ script: $SCRIPT_ROOT+"/fileBrowser", root: "workspace/"});
configRadio();
$("input#nothing").change(function(){
configRadio();
......@@ -25,20 +23,20 @@ $(document).ready( function() {
}
var repo_url = $("input#repo").val();
var email = "";
var name = ""
var name = "";
/* /^(ht|f)tps?:\/\/[a-z0-9-\.]+\.[a-z]{2,4}\/?([^\s<>\#%"\,\{\}\\|\\\^\[\]`]+)?$/ */
if($("input#repo").val() == "" || !repo_url.match(/^[\w\d\.\/:~@_-]+$/)){
if($("input#repo").val() === '' || !repo_url.match(/^[\w\d\.\/:~@_-]+$/)){
$("#error").Popup("Invalid url for the repository", {type:'alert', duration:3000});
return false;
}
if($("input#name").val() == "" || !$("input#name").val().match(/^[\w\d\._-]+$/)){
if($("input#name").val() === '' || !$("input#name").val().match(/^[\w\d\._-]+$/)){
$("#error").Popup("Invalid project name", {type:'alert', duration:3000});
return false;
}
if($("input#user").val() !== ""){
name = $("input#user").val();
}
if($("input#email").val() != "" && $("input#email").val() != "Enter your email adress..."){
if($("input#email").val() !== '' && $("input#email").val() !== "Enter your email adress..."){
if(!$("input#email").val().match(/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/)){
$("#error").Popup("Please enter a valid email adress!", {type:'alert', duration:3000});
return false;
......@@ -77,8 +75,8 @@ $(document).ready( function() {
cloneRequest = $.ajax({
type: "POST",
url: $SCRIPT_ROOT + '/cloneRepository',
data: {repo: repo_url, name: ($("input#workdir").val() + "/"
+ $("input#name").val()), email:email,
data: {repo: repo_url, name: ($("input#workdir").val() + "/" +
$("input#name").val()), email:email,
user:name},
success: function(data){
if(data.code == 1){
......@@ -86,9 +84,7 @@ $(document).ready( function() {
$("#error").Popup("Your repository is cloned!", {type:'confirm', duration:3000});
$("input#repo").val("Enter the url of your repository...");
$("input#name").val("Enter the project name...");
$('#fileTree').fileTree({ root: $("input#workdir").val(), script: $SCRIPT_ROOT + '/readFolder', folderEvent: 'click', expandSpeed: 750, collapseSpeed: 750, multiFolder: false }, function(file) {
selectFile(file);
});
$('#fileNavigator').gsFileManager({ script: $SCRIPT_ROOT+"/fileBrowser", root: "workspace"});
}
else{
$("#error").Popup(data.result, {type:'error'});
......
......@@ -63,15 +63,15 @@ $(document).ready(function() {
$.ajax({
type: 'GET',
url: $SCRIPT_ROOT + '/getParameterXml/xml',
success: function(data) {
if (data.code == 1) {
$('#inline_content').html(content);
success: function(data){
if(data.code == 1){
$("#inline_instance").html(content);
setupEditor(true);
$('.inline').colorbox({inline: true, width: '600px', height: '410px', onComplete: function() {
$("a#inlineInstance").colorbox({inline:true, width: "600px", height: "410px", onComplete:function(){
editor.getSession().setValue(data.result);
}});
$('.inline').click();
$('#loadxml').click(function() {
$("a#inlineInstance").click();
$("#loadxml").click(function(){
//Parse XML file
try {
var xmlDoc = $.parseXML(editor.getSession().getValue()), $xml = $(xmlDoc);
......@@ -109,32 +109,20 @@ $(document).ready(function() {
}
});
function setupFileTree(path) {
var root = $('input#root').val();
if (root == '') return;
if (path) {
root += '/' + path;
$('#tab4>h2').html('File content for <strong>' + path + '</strong>');
}
else {$('#tab4>h2').html('File content for all your partitions');}
$('#fileTree').empty();
$('#fileTree').fileTree({ root: root, script: $SCRIPT_ROOT + '/readFolder', folderEvent: 'click', expandSpeed: 750,
collapseSpeed: 750, multiFolder: false, selectFolder: false }, function(file) {
}, function(file) {
//User have double click on file in to the fileTree
viewFile(file);
});
function setupFileTree(path){
var root = $("input#root").val();
if (root === '') return;
if (path){
root += '/' + path + '/';
}
function viewFile(file) {
//User have double click on file in to the fileTree
loadFileContent(file);
else{root += '/';}
$('#fileNavigator').gsFileManager({ script: $SCRIPT_ROOT+"/fileBrowser", root: root});
}
$('#parameter').load($SCRIPT_ROOT + '/getParameterXml');
$('#update').click(function() {
if ($('#parameter').val() == '') {
$('#error').Popup('Can not save empty value!', {type: 'alert', duration: 3000});
$("#parameter").load($SCRIPT_ROOT + '/getParameterXml');
$("#update").click(function(){
if($("#parameter").val() === ''){
$("#error").Popup("Can not save empty value!", {type:'alert', duration:3000});
}
$.ajax({
type: 'POST',
......@@ -151,47 +139,6 @@ $(document).ready(function() {
});
});
function loadFileContent(file) {
$.ajax({
type: 'POST',
url: $SCRIPT_ROOT + '/checkFileType',
data: 'path=' + file,
success: function(data) {
if (data.code == 1) {
if (data.result == 'text') {
$.ajax({
type: 'POST',
url: $SCRIPT_ROOT + '/getFileContent',
data: {file: file, truncate: 1500},
success: function(data) {
if (data.code == 1) {
$('#inline_content').empty();
$('#inline_content').append('<h2 style="color: #4c6172; font: 18px \'Helvetica Neue\', Helvetica, Arial, sans-serif;">Inspect Instance Content: ' +
file + '</h2>');
$('#inline_content').append('<br/><div class="main_content"><pre id="editor"></pre></div>');
setupEditor();
$('.inline').colorbox({inline: true, width: '847px', onComplete: function() {
editor.getSession().setValue(data.result);
}});
$('.inline').click();
}
else {
$('#error').Popup('Can not load your file, please make sure that you have selected a Software Release', {type: 'alert', duration: 5000});
}
}
});
}
else {
//Can not displays binary file
$('#error').Popup(data.result, {type: 'alert', duration: 5000});
}
}
else {
$('#error').Popup(data.result, {type: 'alert', duration: 5000});
}
}
});
}
function updateParameter() {
var xml = '<?xml version="1.0" encoding="utf-8"?>\n',
software_type = '',
......@@ -233,7 +180,9 @@ $(document).ready(function() {
$txt.keyup(function() {
content = $txt.val().replace(/\n/g, '<br>');
hiddenDiv.html(content);
if (hiddenDiv.height() > $txt.height() && hiddenDiv.height() > 120) {return}
if (hiddenDiv.height() > $txt.height() && hiddenDiv.height() > 120) {
return;
}
$txt.css('height', hiddenDiv.height() + 'px');
});
}
......@@ -241,15 +190,15 @@ $(document).ready(function() {
$.ajax({
type: 'GET',
url: $SCRIPT_ROOT + '/getParameterXml/dict',
success: function(data) {
if (data.code == 1) {
success: function(data){
if(data.code == 1){
var dict = data.result['instance'];
for (propertie in dict) {
$('#add_attribute').click();
var size = Number($('#partitionParameter > tbody > tr').last().attr('id').split('_')[1]);
$('input#txt_' + size).val(propertie);
$('textarea#value_' + size).val(dict[propertie]);
$('textarea#value_' + size).keyup();
for (var propertie in dict){
$("#add_attribute").click();
var size = Number($("#partitionParameter > tbody > tr").last().attr('id').split('_')[1]);
$("input#txt_"+size).val(propertie);
$("textarea#value_"+size).val(dict[propertie]);
$("textarea#value_"+size).keyup();
}
}
else {
......@@ -302,10 +251,10 @@ $(document).ready(function() {
for (var i = 0; i < partitionAmount; i++) {
var elt = $('#slappart' + i + 'Parameter');
var fileId = $('#slappart' + i + 'Files');
if (elt && elt != undefined) elt.click(function() {
if (elt && elt !== undefined) elt.click(function() {
alert($(this).html());
});
if (fileId && fileId != undefined) fileId.click(function() {
if (fileId && fileId !== undefined) fileId.click(function() {
$('#instancetabfiles').click();
setupFileTree($(this).attr('rel'));
});
......
......@@ -2,32 +2,13 @@ $(document).ready( function() {
var editor;
var send = false;
var runnerDir = $("input#runnerdir").val();
var ajaxRun;
fillContent();
$("#softwarelist").change(function(){
$("#info").empty();
$("#info").append("Please select your file or folder into the box...");
$("#reloadfiles").click(function(){
fillContent();
});
function selectFile(file){
var relativeFile = file.replace(runnerDir + "/" + $("#softwarelist").val(), "");
$("#info").empty();
$("#info").append("Selection: " + relativeFile);
return;
}
fillContent();
function fillContent(){
var folder = $("#softwarelist").val();
var elt = $("option:selected", $("#softwarelist"));
if(elt.val() !== "No Software Release found"){
$('#fileTree').fileTree({ root: runnerDir + "/" + folder, script: $SCRIPT_ROOT + '/readFolder',
folderEvent: 'click', expandSpeed: 750, collapseSpeed: 750, multiFolder: false, selectFolder: true }, function(file) {
selectFile(file);
}, function(file){ viewFile(file)});
$("#softcontent").empty();
$("#softcontent").append("File content: " + elt.attr('title'));
}
$('#fileNavigator').gsFileManager({ script: $SCRIPT_ROOT+"/fileBrowser", root: runnerDir});
}
$("#open").click(function(){
......@@ -58,34 +39,28 @@ $(document).ready( function() {
return false;
}
if(send) return;
if(!window.confirm("Do you really want to delete this software release?")){
return;
}
send = false;
var elt = $("option:selected", $("#softwarelist"));
$.ajax({
type: "POST",
url: $SCRIPT_ROOT + '/removeSoftwareDir',
data: "name=" + $("#softwarelist").val(),
data: {md5:$("#softwarelist").val(), title:elt.attr('title')},
success: function(data){
if(data.code == 1){
var folder = $("#softwarelist").val();
$("input#file").val("");
$("#info").empty();
$("#info").append("Please select your file or folder into the box...");
$("#softwarelist").empty();
for(i=0; i<data.result.length; i++){
$("#softwarelist").append('<option value="' + data.result[i]["md5"] +
'" title="' + data.result[i]["title"] +'" rel="' +
data.result[i]["path"] +'">' + data.result[i]["title"] + '</option>');
for(var i=0; i<data.result.length; i++){
$("#softwarelist").append('<option value="' + data.result[i]['md5'] +
'" title="' + data.result[i]['title'] +'" rel="' +
data.result[i]['path'] +'">' + data.result[i]['title'] + '</option>');
}
if(data.result.length < 1){
$("#softwarelist").append('<option>No Software Release found</option>');
$('#fileTree').empty();
}
else{
folder = $("#softwarelist").val();
$('#fileTree').fileTree({ root: runnerDir + "/" + folder, script: $SCRIPT_ROOT + '/readFolder', folderEvent: 'click', expandSpeed: 750,
collapseSpeed: 750, multiFolder: false, selectFolder: true }, function(file) {
selectFile(file);
}, function(file){ viewFile(file)});
}
fillContent();
$("#error").Popup("Operation complete, Selected Software Release has been delete!", {type:'confirm', duration:5000});
}
else{
......@@ -97,54 +72,6 @@ $(document).ready( function() {
return false;
});
function viewFile(file){
//User have double click on file in to the fileTree
var name = file.replace(runnerDir + "/" + $("#softwarelist").val(), "/software");
loadFileContent(file, name);
}
function loadFileContent(file, filename){
$.ajax({
type: "POST",
url: $SCRIPT_ROOT + '/checkFileType',
data: "path=" + file,
success: function(data){
if(data.code == 1){
if (data.result=="text"){
$.ajax({
type: "POST",
url: $SCRIPT_ROOT + '/getFileContent',
data: {file:file, truncate:1500},
success: function(data){
if(data.code == 1){
$("#inline_content").empty();
$("#inline_content").append('<h2 style="color: #4c6172; font: 18px \'Helvetica Neue\', Helvetica, Arial, sans-serif;">Inspect Software Content: ' +
filename +'</h2>');
$("#inline_content").append('<br/><div class="main_content"><pre id="editor"></pre></div>');
setupEditor();
$(".inline").colorbox({inline:true, width: "847px", onComplete:function(){
editor.getSession().setValue(data.result);
}});
$(".inline").click();
}
else{
$("#error").Popup("Can not load your file, please make sure that you have selected a Software Release", {type:'alert', duration:5000});
}
}
});
}
else{
//Can not displays binary file
$("#error").Popup(data.result, {type:'alert', duration:5000});
}
}
else{
$("#error").Popup(data.result, {type:'alert', duration:5000});
}
}
});
}
function setupEditor(){
editor = ace.edit("editor");
editor.setTheme("ace/theme/crimson_editor");
......
......@@ -15,6 +15,7 @@ $(document).ready( function() {
send = true;
var param = {clogin:$("input#clogin").val(), cpwd:$("input#cpwd").val()};
var url = $SCRIPT_ROOT + "/doLogin";
$("#login").removeClass("button").addClass("dsblebutton");
$.post(url, param, function(data) {
if (data.code==1){
location.href = $SCRIPT_ROOT + '/';
......@@ -23,9 +24,11 @@ $(document).ready( function() {
$("#error").Popup(data.result, {type:'alert', duration:3000});
}
})
.error(function() {$("#error").Popup("Cannot send your account identifier please try again!!",
.error(function() {
$("#error").Popup("Cannot send your account identifier please try again!!",
{type:'alert', duration:3000});})
.complete(function() {
$("#login").removeClass('dsblebutton').addClass('button');
send = false;
});
return false;
......
{% extends "layout.html" %}
{% block title %}Adding new repository{% endblock %}
{% block title %}Adding new project{% endblock %}
{% block head %}
{{ super() }}
<link href="{{ url_for('static', filename='css/jqueryFileTree.css', _external=False) }}" rel="stylesheet" type="text/css" media="screen" />
<link href="{{ url_for('static', filename='css/gsFileManager.css', _external=False) }}" rel="stylesheet" type="text/css" media="screen" />
<link href="{{ url_for('static', filename='css/jqueryTabs.css', _external=False) }}" rel="stylesheet" type="text/css" media="screen" />
<script src="{{ url_for('static', filename='js/jquery/jqueryFileTree.js') }}" type="text/javascript" charset="utf-8"></script>
<link href="{{ url_for('static', filename='css/colorbox.css', _external=False) }}" rel="stylesheet" type="text/css" media="screen" />
<script src="{{ url_for('static', filename='js/jquery/gsFileManager.js') }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ url_for('static', filename='js/scripts/folder.js') }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ url_for('static', filename='js/jquery/jqueryTabs.js') }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ url_for('static', filename='js/jquery/jquery.colorbox-min.js') }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ url_for('static', filename='js/ace/ace.js') }}" type="text/javascript" charset="utf-8"></script>
{% endblock %}
{% block body %}
<h2>Clone a repository into your workspace</h2><br/>
<h2>Clone a project repository into your workspace</h2><br/>
<div id="tabContaier">
<ul>
<li><a href="#tab1" class="active">Clone your repository</a></li>
......@@ -71,9 +74,8 @@
<!--Fin tab1-->
</div>
<div id="tab2" class="tabContents">
<h2>Content of your cloned project</h2><br/>
<div id="fileTree" class="file_tree_tabs"></div>
</div>
<div id="fileNavigator"></div>
</div>
</div>
</div>
{% endblock %}
{% extends "layout.html" %}
{% block title %}Edit {{filename}}{% endblock %}
{% block head %}
{{ super() }}
<script src="{{ url_for('static', filename='js/ace/ace.js') }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ url_for('static', filename='js/ace/theme-crimson_editor.js') }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ url_for('static', filename='js/ace/mode-buildout.js') }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ url_for('static', filename='js/scripts/editor.js') }}" type="text/javascript" charset="utf-8"></script>
{% endblock %}
{% block body %}
<form method=post class=add-entry>
<dl>
<dd><h2>Edit file {{ profile|safe }} <a href='#' id="editOption" rel="tooltip" title='Show more option'>[More]</a>:</h2></dd>
<dd><div class='md5sum' id='md5sum'></div></dd>
<dd>
<div class="main_content">
<pre id="editor"></pre>
<input type="hidden" name="profile" id="profile" value="{{ profile|safe }}" />
<input type="hidden" name="workdir" id="workdir" value="{{workDir}}"/>
</div>
</dd>
<dd><input type=submit value=Save id="save" class="button"></dd>
</dl>
</form>
<div id="tooltip-editOption" style="display:none">
<span class="list">MD5 SUM for the current file</span>
<div style="margin-top:3px; margin-bottom:5px;border-bottom: 1px dashed #666666; heigth:1px"></div>
<a id='getmd5' href="#">Get or Update md5sum</a>
<br/><span class="list">Add Project to Develop</span><br/>
<div style="margin-top:3px;border-bottom: 1px dashed #666666; heigth:1px"></div>
<ul id="plist">
{% for name in projectList%}
<li><input type="checkbox" name="develop" value="{{name}}" id="{{name}}">
<label>{{name}}</label></li>
{% endfor %}
</ul>
<br/>
<a href="#" id="adddevelop" class="lshare">Add to profile</a>
</div>
{% endblock %}
......@@ -2,8 +2,6 @@
{% block title %}Instance inspection{% endblock %}
{% block head %}
{{ super() }}
<link href="{{ url_for('static', filename='css/jqueryFileTree.css', _external=False) }}" rel="stylesheet" type="text/css" media="screen" />
<script src="{{ url_for('static', filename='js/jquery/jqueryFileTree.js') }}" type="text/javascript" charset="utf-8"></script>
<link href="{{ url_for('static', filename='css/jqueryTabs.css', _external=False) }}" rel="stylesheet" type="text/css" media="screen" />
<script src="{{ url_for('static', filename='js/jquery/jqueryTabs.js') }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ url_for('static', filename='js/ace/ace.js') }}" type="text/javascript" charset="utf-8"></script>
......@@ -11,6 +9,8 @@
<link href="{{ url_for('static', filename='css/colorbox.css', _external=False) }}" rel="stylesheet" type="text/css" media="screen" />
<script src="{{ url_for('static', filename='js/jquery/jquery.colorbox-min.js') }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ url_for('static', filename='js/scripts/inspectInstance.js') }}" type="text/javascript" charset="utf-8"></script>
<link href="{{ url_for('static', filename='css/gsFileManager.css', _external=False) }}" rel="stylesheet" type="text/css" media="screen" />
<script src="{{ url_for('static', filename='js/jquery/gsFileManager.js') }}" type="text/javascript" charset="utf-8"></script>
{% endblock %}
{% block body %}
<input type='hidden' name='root' id='root' value='{%if file_path != "" %}{{file_path}}{%endif%}' />
......@@ -97,7 +97,7 @@
</div><!-- end tab2 -->
<div id="tab3" class="tabContents">
<div id="softwareType">
<h2 class='hight'>Software Type of main instance</h2>
<h2 class='title'>Software Type of main instance</h2>
<input style="margin-top:5px;" type="text" name="software_type" id="software_type" size="35" value="Software Type here..." />
</div>
<br/>
......@@ -121,17 +121,25 @@
<div class="clear"></div>
</div><!-- end tab3 -->
<div id="tab4" class="tabContents">
<h2>File content for all your partitions</h2>
<div id="fileTree" class="file_tree_tabs" title="Double click to open file"></div>
<!--<h2>File content for all your partitions</h2>
<div id="fileTree" class="file_tree_tabs" title="Double click to open file"></div>-->
{%if file_path != "" %}
<div id="fileNavigator"></div>
<br/>
<a href="#" id="reloadfiles" class="lshare simple">Reload Files</a>
{%else%}
<h2>Your partitions content is empty yet!
<br/>please run your software instance
and look for file result here.
</h2>
{%endif%}
</div><!-- end tab4 -->
</div>
</div>
<!-- This contains the hidden content for inline calls -->
<a class='inline' style='display:none' href="#inline_content">Inline HTML</a>
<a id='inlineInstance' style='display:none' href="#inline_instance">Inline HTML</a>
<div style='display:none'>
<div id='inline_content' style='padding:10px; background:#fff;'>
<div id='inline_instance' style='padding:10px; background:#fff;'>
</div>
</div>
......
......@@ -14,6 +14,7 @@
<link href="{{ url_for('static', filename='css/styles.css', _external=False) }}" rel="stylesheet" type="text/css" media="screen" />
<script src="{{ url_for('static', filename='js/jquery/jquery-1.8.0.min.js') }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ url_for('static', filename='js/jquery/jquery.form.js') }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ url_for('static', filename='js/jquery/popup.js') }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ url_for('static', filename='js/jquery/jqueryToolTip.js') }}" type="text/javascript" charset="utf-8"></script>
<script type=text/javascript>
......@@ -24,6 +25,7 @@
<script type="text/javascript">
$(document).ready(function() {
setInput();
bindRemove();
});
</script>
{% if request.path != '/login' %}
......@@ -67,14 +69,14 @@
<li><a href="{{ url_for('runSoftwareProfile') }}" id="softrun">Run</a></li>
<li><a href="{{ url_for('viewSoftwareLog') }}">Build log</a></li>
<li><a href="{{ url_for('inspectSoftware') }}">Inspect</a></li>
<li><a href="{{ url_for('removeSoftware') }}">Remove all</a></li>
<li><a id="removeSr" href="#">Remove all</a></li>
<li class="space"><span class="title_instance">Instance</span></li>
<li><a href="{{ url_for('editInstanceProfile') }}">Edit</a></li>
<li><a href="{{ url_for('runInstanceProfile') }}" id="instrun">Run</a></li>
<li><a href="{{ url_for('viewInstanceLog') }}">Build log</a></li>
<li><a href="{{ url_for('inspectInstance') }}">Inspect</a></li>
<li><a href="{{ url_for('removeInstance') }}">Remove all</a></li>
<li><a id="removeIst" href="#">Remove all</a></li>
</ul>
</div>
<div class="clear"></div>
......
......@@ -2,19 +2,19 @@
{% block title %}Webrunner software Inspection{% endblock %}
{% block head %}
{{ super() }}
<link href="{{ url_for('static', filename='css/jqueryFileTree.css', _external=False) }}" rel="stylesheet" type="text/css" media="screen" />
<script src="{{ url_for('static', filename='js/jquery/jqueryFileTree.js') }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ url_for('static', filename='js/ace/ace.js') }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ url_for('static', filename='js/ace/theme-crimson_editor.js') }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ url_for('static', filename='js/scripts/inspectSoftware.js') }}" type="text/javascript" charset="utf-8"></script>
<link href="{{ url_for('static', filename='css/colorbox.css', _external=False) }}" rel="stylesheet" type="text/css" media="screen" />
<script src="{{ url_for('static', filename='js/jquery/jquery.colorbox-min.js') }}" type="text/javascript" charset="utf-8"></script>
<link href="{{ url_for('static', filename='css/gsFileManager.css', _external=False) }}" rel="stylesheet" type="text/css" media="screen" />
<script src="{{ url_for('static', filename='js/jquery/gsFileManager.js') }}" type="text/javascript" charset="utf-8"></script>
{% endblock %}
{% block body %}
<h2>Inspect software</h2>
<h2>Inspect software release</h2>
<input type="hidden" name="runnerdir" id="runnerdir" value="{{softwareRoot}}" />
<label for='softwarelist'>Select software: </label>
<label for='softwarelist'>Software Release: </label>
<select name="softwarelist" id="softwarelist">
{%if not softwares %}<option >No Software Release found</option>{% endif %}
{%for soft in softwares %}
......@@ -24,16 +24,8 @@
&nbsp;&nbsp;<button id ="delete" class="button" title="Remove this software">Remove</button>
&nbsp;&nbsp;<button id ="open" class="button" title="Set this software as current software release">Open</button>
<br/><br/>
<h2 id="softcontent">No file or folder to display</h2>
<div id="fileTree" class="file_tree" style='height:200px;' title="Double click to open file"></div>
<div id="file_info" class="file_info">
<span id="info">Please select your file or folder into the box...</span></div>
<!-- This contains the hidden content for inline calls -->
<a class='inline' style='display:none' href="#inline_content">Inline HTML</a>
<div style='display:none'>
<div id='inline_content' style='padding:10px; background:#fff;'>
</div>
</div>
<div id="fileNavigator"></div>
<br/>
<a href="#" id="reloadfiles" class="lshare simple">Reload Files</a>
<br/>
{% endblock %}
......@@ -275,27 +275,58 @@ def runSoftwareWithLock(config):
writePid(slapgrid_pid, slapgrid.pid)
slapgrid.wait()
#Saves the current compile software for re-use
#This uses the new folder create by slapgrid (if not exits yet)
data = loadSoftwareData(config['etc_dir'])
md5 = ""
for path in os.listdir(config['software_root']):
exist = False
for val in data:
if val['md5'] == path:
exist = True
conf = os.path.join(config['etc_dir'], ".project")
if not exist: #save this compile software folder
if os.path.exists(conf):
data.append({"title":getProjectTitle(config), "md5":path,
"path": open(os.path.join(config['etc_dir'],
".project"), 'r').read()})
writeSoftwareData(config['etc_dir'], data)
else:
shutil.rmtree(os.path.join(config['software_root'], path))
break
config_SR_folder(config)
return True
return False
def config_SR_folder(config):
"""Create a symbolik link for each folder in software folder. That allow
user to customize software release folder"""
list = []
config_name = 'slaprunner.config'
for path in os.listdir(config['software_link']):
cfg_path = os.path.join(config['software_link'], path, config_name)
if os.path.exists(cfg_path):
cfg = open(cfg_path, 'r').read().split("#")
if len(cfg) != 2:
continue #there is a broken config file
list.append(cfg[1])
folder_list = os.listdir(config['software_root'])
if len(folder_list) < 1:
return
curent_project = open(os.path.join(config['etc_dir'], ".project"),
'r').read()
projects = curent_project.split("/")
name = projects[len(projects) - 2]
for folder in folder_list:
if folder in list:
continue #this folder is already registered
else:
if not os.path.exists(os.path.join(config['software_link'], name)):
destination = os.path.join(config['software_link'], name)
else:
destination = os.path.join(config['software_link'], folder)
source = os.path.join(config['software_root'], folder)
cfg = os.path.join(destination, config_name)
#create symlink
os.symlink(source, destination)
#write config file
cf = open(cfg, 'w')
cf.write(curent_project+"#"+folder)
cf.close()
def loadSoftwareRList(config):
"""Return list (of dict) of Software Release from symbolik SR folder"""
list = []
config_name = 'slaprunner.config'
for path in os.listdir(config['software_link']):
cfg_path = os.path.join(config['software_link'], path, config_name)
if os.path.exists(cfg_path):
cfg = open(cfg_path, 'r').read().split("#")
if len(cfg) != 2:
continue #there is a broken config file
list.append(dict(md5=cfg[1], path=cfg[0], title=path))
return list
def isInstanceRunning(config):
"""
......@@ -535,6 +566,7 @@ def getProjectList(folder):
project = []
project_list = sorted(os.listdir(folder), key=str.lower)
for elt in project_list:
if os.path.isdir(os.path.join(folder, elt)):
project.append(elt)
return project
......@@ -627,59 +659,26 @@ def getSoftwareReleaseName(config):
return software.replace(' ', '_')
return "No_name"
def loadSoftwareData(basedir):
"""Get All Compiled Softwares Releases name and directory
Agrs:
basedir: base directory of slapos web runner.
Returns:
a dictionnary that contains all compiled Software Release with path"""
import pickle
file_path = os.path.join(basedir, '.softdata')
if not os.path.exists(file_path):
return []
pkl_file = open(file_path, 'rb')
data = pickle.load(pkl_file)
pkl_file.close()
return data
def writeSoftwareData(basedir, data):
"""Save the list of compiled Software Release into a file
Args:
basedir: base directory of slapos web runner.
data: dictionnary data about real name and directory of each software release
"""
import pickle
file_path = os.path.join(basedir, '.softdata')
pkl_file = open(file_path, 'wb')
# Pickle dictionary using protocol 0.
pickle.dump(data, pkl_file)
pkl_file.close()
def removeSoftwareByName(config, folderName):
"""Remove all content of the specified software release
def removeSoftwareByName(config, md5, folderName):
"""Remove all content of the software release specified by md5
Args:
config: slaprunner configuration
foldername: the name given to the software release"""
foldername: the link name given to the software release
md5: the md5 filename given by slapgrid to SR folder"""
if isSoftwareRunning(config) or isInstanceRunning(config):
raise Exception("Software installation or instantiation in progress, cannot remove")
path = os.path.join(config['software_root'], folderName)
path = os.path.join(config['software_root'], md5)
linkpath = os.path.join(config['software_link'], folderName)
if not os.path.exists(path):
raise Exception("Cannot remove software Release: No such file or directory")
if not os.path.exists(linkpath):
raise Exception("Cannot remove software Release: No such file or directory %s" %
('software_root/'+folderName))
svcStopAll(config)
os.unlink(linkpath)
shutil.rmtree(path)
#update compiled software list
data = loadSoftwareData(config['etc_dir'])
i = 0
for p in data:
if p['md5'] == folderName:
del data[i]
writeSoftwareData(config['etc_dir'], data)
break
i = i+1
return data
return loadSoftwareRList(config)
def tail(f, lines=20):
"""
......@@ -775,7 +774,8 @@ def realpath(config, path, check_exist=True):
split_path = path.split('/')
key = split_path[0]
allow_list = {'software_root':config['software_root'], 'instance_root':
config['instance_root'], 'workspace': config['workspace']}
config['instance_root'], 'workspace': config['workspace'],
'software_link':config['software_link']}
if allow_list.has_key(key):
del split_path[0]
path = os.path.join(allow_list[key], *split_path)
......
# -*- coding: utf-8 -*-
from flask import Flask, request, redirect, url_for, \
render_template, g, flash, jsonify, session
render_template, g, flash, jsonify, session, abort, send_file
from utils import *
import os
import shutil
......@@ -9,10 +9,14 @@ import md5
from gittools import cloneRepo, gitStatus, switchBranch, addBranch, getDiff, \
gitPush, gitPull
from flaskext.auth import Auth, AuthUser, login_required, logout
from fileBrowser import fileBrowser
import urllib
app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 20 * 1024 * 1024
auth = Auth(app, login_url_name='login')
auth.user_timeout = 0
file_request = fileBrowser(app.config)
# Setup default flask (werkzeug) parser
import logging
......@@ -95,19 +99,19 @@ def inspectSoftware():
result = ""
else:
result = app.config['software_root']
return render_template('runResult.html', softwareRoot='software_root',
softwares=loadSoftwareData(app.config['etc_dir']))
return render_template('runResult.html', softwareRoot='software_link/',
softwares=loadSoftwareRList(app.config))
#remove content of compiled software release
@login_required()
def removeSoftware():
file_config = os.path.join(app.config['etc_dir'], ".softdata")
if isSoftwareRunning(app.config) or isInstanceRunning(app.config):
flash('Software installation or instantiation in progress, cannot remove')
elif os.path.exists(file_config):
elif os.path.exists(app.config['software_root']):
svcStopAll(app.config)
shutil.rmtree(app.config['software_root'])
os.remove(file_config)
for link in os.listdir(app.config['software_link']):
os.remove(os.path.join(app.config['software_link'], link))
flash('Software removed')
return redirect(url_for('inspectSoftware'))
......@@ -147,7 +151,8 @@ def inspectInstance():
if len(result) == 0:
result = []
return render_template('instanceInspect.html',
file_path=file_content, supervisor=result, slap_status=getSlapStatus(app.config),
file_path=file_content, supervisor=result,
slap_status=getSlapStatus(app.config),
supervisore=result, partition_amount=app.config['partition_amount'])
#Reload instance process ans returns new value to ajax
......@@ -304,7 +309,8 @@ def removeFile():
@login_required()
def removeSoftwareDir():
try:
data = removeSoftwareByName(app.config, request.form['name'])
data = removeSoftwareByName(app.config, request.form['md5'],
request.form['title'])
return jsonify(code=1, result=data)
except Exception, e:
return jsonify(code=0, result=str(e))
......@@ -505,7 +511,8 @@ def configAccount():
account.append(request.form['email'].strip())
account.append(request.form['name'].strip())
code = request.form['rcode'].strip()
recovery_code = open(os.path.join(app.config['etc_dir'], ".rcode"), "r").read()
recovery_code = open(os.path.join(app.config['etc_dir'], ".rcode"),
"r").read()
if code != recovery_code:
return jsonify(code=0, result="Your password recovery code is not valid!")
result = saveSession(app.config, account)
......@@ -515,6 +522,78 @@ def configAccount():
return jsonify(code=1, result="")
return jsonify(code=0, result="Unable to respond to your request, permission denied.")
#Global File Manager
@login_required()
def fileBrowser():
if request.method == 'POST':
filename = request.form.get('filename', '').encode('utf-8')
dir = request.form['dir'].encode('utf-8')
newfilename = request.form.get('newfilename', '').encode('utf-8')
files = request.form.get('files', '').encode('utf-8')
if not request.form.has_key('opt') or not request.form['opt']:
opt = 1
else:
opt = int(request.form['opt'])
else:
opt = int(request.args.get('opt'))
try:
if opt == 1:
#list files and directories
result = file_request.listDirs(dir)
elif opt == 2:
#Create file
result = file_request.makeFile(dir, filename)
elif opt == 3:
#Create directory
result = file_request.makeDirectory(dir, filename)
elif opt == 4:
#Delete a list of files or/and directories
result = file_request.deleteItem(dir, files)
elif opt == 5:
#copy a lis of files or/and directories
result = file_request.copyItem(dir, files)
elif opt == 6:
#rename file or directory
result = file_request.rename(dir, filename, newfilename)
elif opt == 7:
result = file_request.copyItem(dir, files, del_source=True)
elif opt == 8:
#donwload file
filename = request.args.get('filename').encode('utf-8')
result = file_request.downloadFile(request.args.get('dir').encode('utf-8'),
filename)
try:
return send_file(result, attachment_filename=filename, as_attachment=True)
except:
abort(404)
elif opt == 9:
truncateTo = int(request.form.get('truncate', '0'))
result = file_request.readFile(dir, filename)
elif opt == 11:
#Upload file
result = file_request.uploadFile(dir, request.files)
elif opt == 14:
#Copy file or directory as ...
result = file_request.copyAsFile(dir, filename, newfilename)
elif opt == 16:
#zip file
result = file_request.zipFile(dir, filename, newfilename)
elif opt == 17:
#zip file
result = file_request.unzipFile(dir, filename, newfilename)
else:
result = "ARGS PARSE ERROR: Bad option..."
except Exception, e:
return str(e)
return result
@login_required()
def editFile():
return render_template('editFile.html', workDir='workspace',
profile=urllib.unquote(request.args.get('profile', '')),
projectList=getProjectList(app.config['workspace']),
filename=urllib.unquote(request.args.get('filename', '')))
#Setup List of URLs
app.add_url_rule('/', 'home', home)
app.add_url_rule('/editSoftwareProfile', 'editSoftwareProfile', editSoftwareProfile)
......@@ -561,3 +640,5 @@ app.add_url_rule("/saveParameterXml", 'saveParameterXml', saveParameterXml, meth
app.add_url_rule("/getPath", 'getPath', getPath, methods=['POST'])
app.add_url_rule("/myAccount", 'myAccount', myAccount)
app.add_url_rule("/updateAccount", 'updateAccount', updateAccount, methods=['POST'])
app.add_url_rule("/fileBrowser", 'fileBrowser', fileBrowser, methods=['GET', 'POST'])
app.add_url_rule("/editFile", 'editFile', editFile, methods=['GET'])
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment