Remove flask YAML web editor from Spyglass

Spyglass was originally built with a web-based YAML editor.
Unfortunately, the presence of the editor has caused some problems. It
can cause the Docker container to freeze before creating the
intermediary YAML file. The execution of the flask app is also the
root cause for the Bandit B104 errors and B605 error.

Since the target audience for Spyglass is developers, it can be
assumed that they will have access to an editor with support for YAML
files. Having a web-based version of the YAML editor is unnecessary and
will just result in more code to maintain in the future.

Removes the editor script from utils.

Removes the yaml-editor entry point from the package.

Removes references to the yaml-editor from the CLI and engine.

Resolves all known Bandit errors.

In the future, a pause in execution could be provided to allow users to
make quick edits. Log messages could also notify users when a
placeholder value is inserted in the intermediary so they can fix it.

Change-Id: Ibc37e61f93b33904ea839e12fe5a8d586985e0b1
This commit is contained in:
Ian Pittwood
2019-04-08 15:57:44 -05:00
parent 6149c4a1a5
commit 8dd891aced
15 changed files with 3 additions and 601 deletions

View File

@@ -1,170 +0,0 @@
# Copyright 2018 AT&T Intellectual Property. All other rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an 'AS IS' BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import logging
import os
import sys
import click
import yaml
from flask import Flask, request, render_template, send_from_directory
from flask_bootstrap import Bootstrap
app_path = os.path.dirname(os.path.abspath(__file__))
app = Flask(
"Yaml Editor!",
template_folder=os.path.join(app_path, "templates"),
static_folder=os.path.join(app_path, "static"),
)
Bootstrap(app)
logging.getLogger("werkzeug").setLevel(logging.ERROR)
LOG = app.logger
@app.route("/favicon.ico")
def favicon():
return send_from_directory(app.static_folder, "favicon.ico")
@app.route("/", methods=["GET", "POST"])
def index():
"""Renders index page to edit provided yaml file."""
LOG.info("Rendering yaml file for editing")
with open(app.config["YAML_FILE"]) as file_obj:
data = yaml.safe_load(file_obj)
return render_template(
"yaml.html",
data=json.dumps(data),
change_str=app.config["STRING_TO_CHANGE"],
)
@app.route("/save", methods=["POST"])
def save():
"""Save current progress on file."""
LOG.info("Saving edited inputs from user to yaml file")
out = request.json.get("yaml_data")
with open(app.config["YAML_FILE"], "w") as file_obj:
yaml.safe_dump(out, file_obj, default_flow_style=False)
return "Data saved successfully!"
@app.route("/saveExit", methods=["POST"])
def save_exit():
"""Save current progress on file and shuts down the server."""
LOG.info(
"Saving edited inputs from user to yaml file and shutting"
" down server"
)
out = request.json.get("yaml_data")
with open(app.config["YAML_FILE"], "w") as file_obj:
yaml.safe_dump(out, file_obj, default_flow_style=False)
func = request.environ.get("werkzeug.server.shutdown")
if func:
func()
return "Saved successfully, Shutting down app! You may close the tab!"
@app.errorhandler(404)
def page_not_found(e):
"""Serves 404 error."""
LOG.info("User tried to access unavailable page.")
return "<h1>404: Page not Found!</h1>"
def run(*args, **kwargs):
"""Starts the server."""
LOG.info("Initiating web server for yaml editing")
port = kwargs.get("port", None)
if not port:
port = 8161
app.run(host="0.0.0.0", port=port, debug=False)
@click.command()
@click.option(
"--file",
"-f",
required=True,
type=click.File(),
multiple=False,
help="Path with file name to the intermediary yaml file.",
)
@click.option(
"--host",
"-h",
default="0.0.0.0",
type=click.STRING,
multiple=False,
help="Optional host parameter to run Flask on.",
)
@click.option(
"--port",
"-p",
default=8161,
type=click.INT,
multiple=False,
help="Optional port parameter to run Flask on.",
)
@click.option(
"--string",
"-s",
default="#CHANGE_ME",
type=click.STRING,
multiple=False,
help="Text which is required to be changed on yaml file.",
)
def main(*args, **kwargs):
LOG.setLevel(logging.INFO)
LOG.info("Initiating yaml-editor")
try:
yaml.safe_load(kwargs["file"])
except yaml.YAMLError as e:
LOG.error("EXITTING - Please provide a valid yaml file.")
if hasattr(e, "problem_mark"):
mark = e.problem_mark
LOG.error(
"Error position: ({0}:{1})".format(
mark.line + 1, mark.column + 1
)
)
sys.exit(2)
except Exception:
LOG.error("EXITTING - Please provide a valid yaml file.")
sys.exit(2)
LOG.info(
"""
##############################################################################
Please go to http://{0}:{1}/ to edit your yaml file.
##############################################################################
""".format(
kwargs["host"], kwargs["port"]
)
)
app.config["YAML_FILE"] = kwargs["file"].name
app.config["STRING_TO_CHANGE"] = kwargs["string"]
run(*args, **kwargs)
if __name__ == "__main__":
"""Invoked when used as a script."""
main()

View File

@@ -1,92 +0,0 @@
// Copyright 2018 AT&T Intellectual Property. All other rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This file includes all the frond-end functionality being used for the
// yaml editor application.
/**
* Calls /save URL to save edit progress.
* @param {String} data Stringified JSON data.
*/
function save(data) {
$.ajax({
type: 'POST',
url: '/save',
data: data,
success: function(res) {
setTimeout(function() { alert(res); }, 3);
},
contentType: 'application/json;charset=UTF-8'
});
}
/**
* Calls /saveExit URL to save edit progress and shut down web server.
* @param {String} data Stringified JSON data.
*/
function saveAndExit(data) {
$.ajax({
type: 'POST',
url: '/saveExit',
data: data,
success: function(res) {
setTimeout(function() { alert(res); }, 3);
},
contentType: 'application/json;charset=UTF-8'
});
}
/**
* Collects and validates data from textarea.
* @returns {String} Stringified JSON data.
*/
function getSimpleData() {
var data = $("#yaml_data").val();
try {
var index = data.indexOf(changeStr)
if (index != -1) {
var lineNum = data.substring(0, index).split('\n').length;
alert('Please change value on line '+ lineNum + '!')
return null
}
data = jsyaml.load(data)
}
catch(err) {
alert(err)
return null
}
return JSON.stringify({yaml_data : data})
}
/**
* Function to save edit progress.
*/
function saveSimple() {
var data = getSimpleData()
if (data) {
save(data)
}
}
/**
* Function to save edit progress and shut down web server.
*/
function saveExitSimple() {
var data = getSimpleData()
if (data) {
saveAndExit(data)
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,68 +0,0 @@
/**
* jQuery Lined Textarea Plugin
* http://alan.blog-city.com/jquerylinedtextarea.htm
*
* Copyright (c) 2010 Alan Williamson
*
* Released under the MIT License:
* http://www.opensource.org/licenses/mit-license.php
*
* Usage:
* Displays a line number count column to the left of the textarea
*
* Class up your textarea with a given class, or target it directly
* with JQuery Selectors
*
* $(".lined").linedtextarea({
* selectedLine: 10,
* selectedClass: 'lineselect'
* });
*
*/
.linedwrap {
border: 1px solid #c0c0c0;
padding: 3px;
}
.linedtextarea {
padding: 0px;
margin: 0px;
}
.linedtextarea textarea, .linedwrap .codelines .lineno {
font-size: 10pt;
font-family: monospace;
line-height: normal !important;
}
.linedtextarea textarea {
padding-right:0.3em;
padding-top:0.3em;
border: 0;
}
.linedwrap .lines {
margin-top: 0px;
width: 50px;
float: left;
overflow: hidden;
border-right: 1px solid #c0c0c0;
margin-right: 10px;
}
.linedwrap .codelines {
padding-top: 5px;
}
.linedwrap .codelines .lineno {
color:#AAAAAA;
padding-right: 0.5em;
padding-top: 0.0em;
text-align: right;
white-space: nowrap;
}
.linedwrap .codelines .lineselect {
color: red;
}

View File

@@ -1,126 +0,0 @@
/**
* jQuery Lined Textarea Plugin
* http://alan.blog-city.com/jquerylinedtextarea.htm
*
* Copyright (c) 2010 Alan Williamson
*
* Version:
* $Id: jquery-linedtextarea.js 464 2010-01-08 10:36:33Z alan $
*
* Released under the MIT License:
* http://www.opensource.org/licenses/mit-license.php
*
* Usage:
* Displays a line number count column to the left of the textarea
*
* Class up your textarea with a given class, or target it directly
* with JQuery Selectors
*
* $(".lined").linedtextarea({
* selectedLine: 10,
* selectedClass: 'lineselect'
* });
*
* History:
* - 2010.01.08: Fixed a Google Chrome layout problem
* - 2010.01.07: Refactored code for speed/readability; Fixed horizontal sizing
* - 2010.01.06: Initial Release
*
*/
(function($) {
$.fn.linedtextarea = function(options) {
// Get the Options
var opts = $.extend({}, $.fn.linedtextarea.defaults, options);
/*
* Helper function to make sure the line numbers are always
* kept up to the current system
*/
var fillOutLines = function(codeLines, h, lineNo){
while ( (codeLines.height() - h ) <= 0 ){
if ( lineNo == opts.selectedLine )
codeLines.append("<div class='lineno lineselect'>" + lineNo + "</div>");
else
codeLines.append("<div class='lineno'>" + lineNo + "</div>");
lineNo++;
}
return lineNo;
};
/*
* Iterate through each of the elements are to be applied to
*/
return this.each(function() {
var lineNo = 1;
var textarea = $(this);
/* Turn off the wrapping of as we don't want to screw up the line numbers */
textarea.attr("wrap", "off");
textarea.css({resize:'none'});
var originalTextAreaWidth = textarea.outerWidth();
/* Wrap the text area in the elements we need */
textarea.wrap("<div class='linedtextarea'></div>");
var linedTextAreaDiv = textarea.parent().wrap("<div class='linedwrap' style='width:" + originalTextAreaWidth + "px'></div>");
var linedWrapDiv = linedTextAreaDiv.parent();
linedWrapDiv.prepend("<div class='lines' style='width:50px'></div>");
var linesDiv = linedWrapDiv.find(".lines");
linesDiv.height( textarea.height() + 6 );
/* Draw the number bar; filling it out where necessary */
linesDiv.append( "<div class='codelines'></div>" );
var codeLinesDiv = linesDiv.find(".codelines");
lineNo = fillOutLines( codeLinesDiv, linesDiv.height(), 1 );
/* Move the textarea to the selected line */
if ( opts.selectedLine != -1 && !isNaN(opts.selectedLine) ){
var fontSize = parseInt( textarea.height() / (lineNo-2) );
var position = parseInt( fontSize * opts.selectedLine ) - (textarea.height()/2);
textarea[0].scrollTop = position;
}
/* Set the width */
var sidebarWidth = linesDiv.outerWidth();
var paddingHorizontal = parseInt( linedWrapDiv.css("border-left-width") ) + parseInt( linedWrapDiv.css("border-right-width") ) + parseInt( linedWrapDiv.css("padding-left") ) + parseInt( linedWrapDiv.css("padding-right") );
var linedWrapDivNewWidth = originalTextAreaWidth - paddingHorizontal;
var textareaNewWidth = originalTextAreaWidth - sidebarWidth - paddingHorizontal - 20;
textarea.width( textareaNewWidth );
linedWrapDiv.width( linedWrapDivNewWidth );
/* React to the scroll event */
textarea.scroll( function(tn){
var domTextArea = $(this)[0];
var scrollTop = domTextArea.scrollTop;
var clientHeight = domTextArea.clientHeight;
codeLinesDiv.css( {'margin-top': (-1*scrollTop) + "px"} );
lineNo = fillOutLines( codeLinesDiv, scrollTop + clientHeight, lineNo );
});
/* Should the textarea get resized outside of our control */
textarea.resize( function(tn){
var domTextArea = $(this)[0];
linesDiv.height( domTextArea.clientHeight + 6 );
});
});
};
// default options
$.fn.linedtextarea.defaults = {
selectedLine: -1,
selectedClass: 'lineselect'
};
})(jQuery);

File diff suppressed because one or more lines are too long

View File

@@ -1,38 +0,0 @@
{% extends "bootstrap/base.html" %}
{% block title %}YAML Editor{% endblock %}
{% block styles %}
{{super()}}
<link href="{{ url_for('static', filename='jquery-linedtextarea.css') }}" rel="stylesheet">
{% endblock %}
{% block scripts %}
{{super()}}
<script src="{{ url_for('static', filename='js-yaml.min.js') }}"></script>
<script src="{{ url_for('static', filename='jquery-linedtextarea.js') }}"></script>
<script type="text/javascript">
var changeStr = '{{ change_str }}'
$(document).ready(function(){
$("#yaml_data").val(jsyaml.dump(JSON.parse('{{ data|safe }}')))
$("#yaml_data").linedtextarea();
});
</script>
<script src="{{ url_for('static', filename='app.js') }}"></script>
{% endblock %}
{% block content %}
<div class="container" style="margin-top:30px;">
<div class="form-group">
<pre>Edit your YAML (Update corresponding fields with {{ change_str }} text):</pre>
<div>
<textarea class="form-control linedtextarea" id='yaml_data' style="height: 500px;box-shadow: none;"></textarea>
</div>
</div>
<div class="form-group pull-right">
<button type="button" onclick="saveSimple()" class="btn btn-lg btn-success ">Save</button>
<button type="button" onclick="saveExitSimple()" class="btn btn-lg btn-primary ">Save and Exit</button>
</div>
</div>
{% endblock %}