diff --git a/src/api/api_document.py b/src/api/api_document.py
index 81d8fc3..54dac1c 100644
--- a/src/api/api_document.py
+++ b/src/api/api_document.py
@@ -1,7 +1,5 @@
from flask import Blueprint, request
-from markupsafe import escape
from web_utils.get_arg import get_arg
-from web_utils.run import run
import os
from data.document import Document
@@ -18,14 +16,10 @@ def build():
if doc.get_api_key() != apikey:
raise Exception("Invalid API key")
- output = ""
- output += "\n# Pulling source...\n"
- output += doc.pull()
+ build_task = doc.build()
+ build_task.join()
- output += "\n# Compiling...\n"
- output += doc.build()
-
- return output.replace('\n', '
')
+ return build_task.get_output_str().replace('\n', '
')
@bp.route('/clone')
def clone():
@@ -34,6 +28,7 @@ def clone():
branch = get_arg('branch', 'master')
source_dir = get_arg('source', 'source')
- output = Document.clone(repo, branch, doc_name, source_dir)
+ clone_task = Document.clone(repo, branch, doc_name, source_dir)
+ clone_task.join()
- return output.replace('\n', '
')
+ return clone_task.get_output_str().replace('\n', '
')
diff --git a/src/api/api_task.py b/src/api/api_task.py
new file mode 100644
index 0000000..816f072
--- /dev/null
+++ b/src/api/api_task.py
@@ -0,0 +1,20 @@
+import time
+from flask import Blueprint, request
+from web_utils.get_arg import get_arg
+from web_utils.task import Task
+
+bp = Blueprint('api_task', __name__, url_prefix='/api/task')
+
+@bp.route('/log')
+def log():
+ task_id = get_arg('task_id')
+ from_char = int(get_arg('from', '0'))
+
+ task = Task.get(task_id)
+ if task == None:
+ return { "task_finished": True, "new_output": "" }
+
+ while task.is_alive() and len(task.get_output_str()) <= from_char:
+ time.sleep(100)
+
+ return { "task_finished": not task.is_alive(), "new_output": task.get_output_str()[from_char:-1] }
diff --git a/src/app.py b/src/app.py
index 5570603..be23dc9 100644
--- a/src/app.py
+++ b/src/app.py
@@ -36,6 +36,9 @@ def create_app():
from api import api_document
app.register_blueprint(api_document.bp)
+ from api import api_task
+ app.register_blueprint(api_task.bp)
+
from web import web_document
app.register_blueprint(web_document.bp)
diff --git a/src/data/document.py b/src/data/document.py
index b844ea9..87aa456 100644
--- a/src/data/document.py
+++ b/src/data/document.py
@@ -1,7 +1,7 @@
import os
import uuid
from flask import current_app
-from web_utils.run import run
+from web_utils.task import ProcessTask
import shutil
from unicodedata import normalize
import string
@@ -45,11 +45,15 @@ class Document:
def build(self):
#venv_path = os.getenv('VIRTUAL_ENV')
- cmd = "sphinx-build -M html \""+self.doc_path + "/repo/source\" \""+self.doc_path+"/build\""
- return run(cmd)
-
- def pull(self):
- return run("cd \"" + self.doc_path + "/repo\" && git pull")
+
+ cmd = []
+ cmd.append(['git', 'pull'])
+ cmd.append(['sphinx-build', '-M', 'html', self.doc_path + "/repo/source", self.doc_path + "/build"])
+
+ task = ProcessTask(cmd, cwd = self.doc_path + "/repo")
+ task.start()
+
+ return task
def delete(self):
shutil.rmtree(self.doc_path)
@@ -90,24 +94,23 @@ class Document:
apikey = str(uuid.uuid4())
target_dir = doc_path + "/repo"
+ os.makedirs(target_dir, exist_ok = True)
+ with open(doc_path + "/apikey", "wb") as apikey_file:
+ apikey_file:write(apikey)
+
+ cmd = []
+ cmd.append(['git', 'init', '--initial-branch=' + branch])
+ cmd.append(['git', 'remote', 'add', '-f', 'origin', repo])
+ cmd.append(['git', 'sparse-checkout', 'init'])
+ cmd.append(['git', 'sparse-checkout', 'set', source_dir])
+ cmd.append(['git', 'pull', 'origin', branch])
+ cmd.append(['git', 'branch', '--set-upstream-to=origin/' + branch, branch])
- cmd = ""
- cmd += "mkdir -p \"" + target_dir + "\"\n"
- cmd += "echo \""+apikey+"\" > \"" + doc_path + "/apikey\"\n"
- cmd += "cd \"" + target_dir + "\"\n"
- cmd += "git init \"--initial-branch=" + branch + "\"\n"
- cmd += "git remote add -f origin \"" + repo + "\"\n"
- cmd += "git sparse-checkout init\n"
- cmd += "git sparse-checkout set \"" + source_dir + "\"\n"
- cmd += "git pull origin \"" + branch + "\"\n"
- cmd += "git branch \"--set-upstream-to=origin/" + branch + "\" \"" +branch + "\""
+ task = ProcessTask(cmd, cwd = target_dir)
+ task.on_fail(lambda : shutil.rmtree(doc_path, ignore_errors = True))
+ task.start()
- try:
- return run(cmd)
- except Exception as e:
- # cloning failed, clean up and raise the same exception again
- shutil.rmtree(doc_path)
- raise e
+ return task
@staticmethod
def list():
diff --git a/src/static/app.js b/src/static/app.js
index d6aa92c..49a6744 100644
--- a/src/static/app.js
+++ b/src/static/app.js
@@ -1,4 +1,4 @@
-var confirm_elements = document.querySelectorAll('a[data-confirm]');
+var confirm_elements = document.querySelectorAll('[data-confirm]');
for (let elt of confirm_elements)
{
elt.addEventListener('click', (e) => {
@@ -6,3 +6,12 @@ for (let elt of confirm_elements)
e.preventDefault();
}, false);
}
+
+var buttons = document.querySelectorAll('.button');
+for (let elt of buttons)
+{
+ elt.addEventListener('click', (e) => {
+ if(elt.classList.contains('disabled'))
+ e.preventDefault();
+ }, false);
+}
diff --git a/src/static/log-stream.js b/src/static/log-stream.js
new file mode 100644
index 0000000..50516fe
--- /dev/null
+++ b/src/static/log-stream.js
@@ -0,0 +1,34 @@
+function log_stream(element, logUrl) {
+ element.innerText = "";
+
+ function fetchMore() {
+ fetch(logUrl + "&from=" + element.innerText.length)
+ .then(response => response.text())
+ .then(jsonStr => {
+ let json = JSON.parse(jsonStr);
+
+ element.innerText += json.new_output;
+
+ const scrollOffset = 60;
+ const bodyTop = document.body.getBoundingClientRect().top;
+ const viewportHeight = window.innerHeight;
+ const elementBottom = element.getBoundingClientRect().bottom;
+
+ window.scrollTo({
+ top: elementBottom - viewportHeight - bodyTop + scrollOffset
+ });
+
+ if(json.task_finished) {
+ let validationButtonId = element.getAttribute('data-validation-button-id');
+ if(validationButtonId) {
+ document.getElementById(validationButtonId).classList.remove('disabled', false);
+ }
+ }
+ else {
+ setTimeout(fetchMore, 100);
+ }
+ });
+ }
+
+ fetchMore();
+}
diff --git a/src/static/style.css b/src/static/style.css
index e69de29..2d1acf8 100644
--- a/src/static/style.css
+++ b/src/static/style.css
@@ -0,0 +1,23 @@
+.button {
+ display: inline-block;
+ border: 1px solid gray;
+ border-radius: 4px;
+ padding: 3px 10px;
+ margin: 2px;
+ color: black;
+}
+
+a.button {
+ text-decoration: none;
+}
+
+.button.danger {
+ color: darkred;
+ border-color: darkred;
+}
+
+.button.disabled {
+ color: lightgray;
+ border-color: lightgray;
+ cursor: default;
+}
diff --git a/src/templates/admin/command_output.html b/src/templates/admin/command_output.html
index 7f7d776..3848e27 100644
--- a/src/templates/admin/command_output.html
+++ b/src/templates/admin/command_output.html
@@ -1,8 +1,13 @@
-{% extends 'base.html' %}
+{% extends 'base.html' %}
{% block title %}Exécution...{% endblock %}
{% block content %}
-
{{ output }}- OK +
Chargement...+ OK + + + {% endblock %} diff --git a/src/templates/admin/document/manage.html b/src/templates/admin/document/manage.html index 483caf1..7323fc5 100644 --- a/src/templates/admin/document/manage.html +++ b/src/templates/admin/document/manage.html @@ -6,7 +6,7 @@
URL permettant de déclencher la compilation : {{ url_for('api_document.build', doc = doc.doc_name, branch = doc.branch, apikey = doc.get_api_key(), _external = True) }}
Consulter