summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/toaster/toastergui
diff options
context:
space:
mode:
authorAlexandru DAMIAN <alexandru.damian@intel.com>2015-02-16 17:47:07 +0000
committerRichard Purdie <richard.purdie@linuxfoundation.org>2015-02-20 12:58:19 +0000
commitc368d83bd6b34c2420c3d1d7269d8dc2edba1ce9 (patch)
treed6a905444fe2ea0f0313bc4b848430108ac17388 /bitbake/lib/toaster/toastergui
parenta574f293fe16612df446d3b7fef71adcab4773e9 (diff)
downloadpoky-c368d83bd6b34c2420c3d1d7269d8dc2edba1ce9.tar.gz
bitbake: toaster: bitbake cooker log saving and downloading
This patch brings in cooker log saving and proper download links. * toasterui will now write the cooker log file if running in managed mode * the BuildRequest has a new state, REQ_ARCHIVE, indicating that the build is completed, and the artifacts are ready to be grabbed * the runbuild test execution commands will gather needed artifacts, and save them to a storage directory selected during Toaster setup. * the build dashboard, project builds and all builds pages have permanent links for the cooker log [YOCTO #7220] [YOCTO #7206] (Bitbake rev: fad80e36c9da663b000cdf2cb3c75440c6431d84) Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/toaster/toastergui')
-rw-r--r--bitbake/lib/toaster/toastergui/templates/build.html9
-rw-r--r--bitbake/lib/toaster/toastergui/templates/builddashboard.html11
-rw-r--r--bitbake/lib/toaster/toastergui/templates/managed_builds.html9
-rw-r--r--bitbake/lib/toaster/toastergui/templates/projectbuilds.html14
-rw-r--r--bitbake/lib/toaster/toastergui/templates/unavailable_artifact.html17
-rwxr-xr-xbitbake/lib/toaster/toastergui/views.py94
6 files changed, 118 insertions, 36 deletions
diff --git a/bitbake/lib/toaster/toastergui/templates/build.html b/bitbake/lib/toaster/toastergui/templates/build.html
index e71e38feb9..684ec65884 100644
--- a/bitbake/lib/toaster/toastergui/templates/build.html
+++ b/bitbake/lib/toaster/toastergui/templates/build.html
@@ -40,7 +40,9 @@
40 <!-- Table data rows; the order needs to match the order of "tablecols" definitions; and the <td class value needs to match the tablecols clclass value for show/hide buttons to work --> 40 <!-- Table data rows; the order needs to match the order of "tablecols" definitions; and the <td class value needs to match the tablecols clclass value for show/hide buttons to work -->
41 {% for build in objects %} 41 {% for build in objects %}
42 <tr class="data"> 42 <tr class="data">
43 <td class="outcome"><a href="{% url "builddashboard" build.id %}">{%if build.outcome == build.SUCCEEDED%}<i class="icon-ok-sign success"></i>{%elif build.outcome == build.FAILED%}<i class="icon-minus-sign error"></i>{%else%}{%endif%}</a></td> 43 <td class="outcome">
44 <a href="{% url "builddashboard" build.id %}">{%if build.outcome == build.SUCCEEDED%}<i class="icon-ok-sign success"></i>{%elif build.outcome == build.FAILED%}<i class="icon-minus-sign error"></i>{%else%}{%endif%}</a> &nbsp;
45 </td>
44 <td class="target">{% for t in build.target_set.all %} <a href="{% url "builddashboard" build.id %}"> {{t.target}} </a> <br />{% endfor %}</td> 46 <td class="target">{% for t in build.target_set.all %} <a href="{% url "builddashboard" build.id %}"> {{t.target}} </a> <br />{% endfor %}</td>
45 <td class="machine"><a href="{% url "builddashboard" build.id %}">{{build.machine}}</a></td> 47 <td class="machine"><a href="{% url "builddashboard" build.id %}">{{build.machine}}</a></td>
46 <td class="started_on"><a href="{% url "builddashboard" build.id %}">{{build.started_on|date:"d/m/y H:i"}}</a></td> 48 <td class="started_on"><a href="{% url "builddashboard" build.id %}">{{build.started_on|date:"d/m/y H:i"}}</a></td>
@@ -61,11 +63,6 @@
61 <td class="errors_no"> 63 <td class="errors_no">
62 {% if build.errors_no %} 64 {% if build.errors_no %}
63 <a class="errors_no error" href="{% url "builddashboard" build.id %}#errors">{{build.errors_no}} error{{build.errors_no|pluralize}}</a> 65 <a class="errors_no error" href="{% url "builddashboard" build.id %}#errors">{{build.errors_no}} error{{build.errors_no|pluralize}}</a>
64 {% if MANAGED and build.project %}
65 <a href="{% url 'build_artifact' build.id "cookerlog" build.id %}">
66 <i class="icon-download-alt" title="" data-original-title="Download build log"></i>
67 </a>
68 {% endif %}
69 {%endif%} 66 {%endif%}
70 </td> 67 </td>
71 <td class="warnings_no">{% if build.warnings_no %}<a class="warnings_no warning" href="{% url "builddashboard" build.id %}#warnings">{{build.warnings_no}} warning{{build.warnings_no|pluralize}}</a>{%endif%}</td> 68 <td class="warnings_no">{% if build.warnings_no %}<a class="warnings_no warning" href="{% url "builddashboard" build.id %}#warnings">{{build.warnings_no}} warning{{build.warnings_no|pluralize}}</a>{%endif%}</td>
diff --git a/bitbake/lib/toaster/toastergui/templates/builddashboard.html b/bitbake/lib/toaster/toastergui/templates/builddashboard.html
index 2458cdb6d1..c0898e291d 100644
--- a/bitbake/lib/toaster/toastergui/templates/builddashboard.html
+++ b/bitbake/lib/toaster/toastergui/templates/builddashboard.html
@@ -36,7 +36,11 @@
36{% endif %} 36{% endif %}
37 <span > <i class="icon-warning-sign yellow"></i><strong><a href="#warnings" class="warning show-warnings"> {{build.warnings_no}} warning{{build.warnings_no|pluralize}}</a></strong></span> 37 <span > <i class="icon-warning-sign yellow"></i><strong><a href="#warnings" class="warning show-warnings"> {{build.warnings_no}} warning{{build.warnings_no|pluralize}}</a></strong></span>
38{% endif %} 38{% endif %}
39 <span class="pull-right">Build time: <a href="{% url 'buildtime' build.pk %}">{{ build.timespent|sectohms }}</a></span> 39 <span class="pull-right">Build time: <a href="{% url 'buildtime' build.pk %}">{{ build.timespent|sectohms }}</a> &nbsp;
40 {% if MANAGED and build.project %}
41 <a class="btn {%if build.outcome == build.SUCCEEDED%}btn-success{%else%}btn-danger{%endif%} pull-right" href="{% url 'build_artifact' build.id "cookerlog" build.id %}">Download build log</a>
42 {% endif %}
43 </span>
40{%endif%} 44{%endif%}
41 </div> 45 </div>
42 {% if build.toaster_exceptions.count > 0 %} 46 {% if build.toaster_exceptions.count > 0 %}
@@ -54,10 +58,7 @@
54<div class="accordion span10 pull-right" id="errors"> 58<div class="accordion span10 pull-right" id="errors">
55 <div class="accordion-group"> 59 <div class="accordion-group">
56 <div class="accordion-heading"> 60 <div class="accordion-heading">
57 {% if MANAGED and build.project %} 61 <a class="accordion-toggle error toggle-errors">
58 <a class="btn btn-large pull-right" href="{% url 'build_artifact' build.id "cookerlog" build.id %}" style="margin:15px;">Download build log</a>
59 {% endif %}
60 <a class="accordion-toggle error toggle-errors">
61 <h2 id="error-toggle"> 62 <h2 id="error-toggle">
62 <i class="icon-minus-sign"></i> 63 <i class="icon-minus-sign"></i>
63 {{build.errors_no}} error{{build.errors_no|pluralize}} 64 {{build.errors_no}} error{{build.errors_no|pluralize}}
diff --git a/bitbake/lib/toaster/toastergui/templates/managed_builds.html b/bitbake/lib/toaster/toastergui/templates/managed_builds.html
index 121ad07898..a4db55b967 100644
--- a/bitbake/lib/toaster/toastergui/templates/managed_builds.html
+++ b/bitbake/lib/toaster/toastergui/templates/managed_builds.html
@@ -46,7 +46,14 @@
46 <!-- Table data rows; the order needs to match the order of "tablecols" definitions; and the <td class value needs to match the tablecols clclass value for show/hide buttons to work --> 46 <!-- Table data rows; the order needs to match the order of "tablecols" definitions; and the <td class value needs to match the tablecols clclass value for show/hide buttons to work -->
47 {% for buildrequest in objects %}{% if buildrequest.build %} {% with build=buildrequest.build %} {# if we have a build, just display it #} 47 {% for buildrequest in objects %}{% if buildrequest.build %} {% with build=buildrequest.build %} {# if we have a build, just display it #}
48 <tr class="data"> 48 <tr class="data">
49 <td class="outcome"><a href="{% url "builddashboard" build.id %}">{%if build.outcome == build.SUCCEEDED%}<i class="icon-ok-sign success"></i>{%elif build.outcome == build.FAILED%}<i class="icon-minus-sign error"></i>{%else%}{%endif%}</a></td> 49 <td class="outcome"><a href="{% url "builddashboard" build.id %}">{%if build.outcome == build.SUCCEEDED%}<i class="icon-ok-sign success"></i>{%elif build.outcome == build.FAILED%}<i class="icon-minus-sign error"></i>{%else%}{%endif%}</a>
50 {% if build.project %}
51 &nbsp; <a href="{% url 'build_artifact' build.id "cookerlog" build.id %}">
52 <i class="icon-download-alt" title="" data-original-title="Download build log"></i>
53 </a>
54 {% endif %}
55
56 </td>
50 <td class="target">{% for t in build.target_set.all %} <a href="{% url "builddashboard" build.id %}"> {{t.target}} </a> <br />{% endfor %}</td> 57 <td class="target">{% for t in build.target_set.all %} <a href="{% url "builddashboard" build.id %}"> {{t.target}} </a> <br />{% endfor %}</td>
51 <td class="machine"><a href="{% url "builddashboard" build.id %}">{{build.machine}}</a></td> 58 <td class="machine"><a href="{% url "builddashboard" build.id %}">{{build.machine}}</a></td>
52 <td class="started_on"><a href="{% url "builddashboard" build.id %}">{{build.started_on|date:"d/m/y H:i"}}</a></td> 59 <td class="started_on"><a href="{% url "builddashboard" build.id %}">{{build.started_on|date:"d/m/y H:i"}}</a></td>
diff --git a/bitbake/lib/toaster/toastergui/templates/projectbuilds.html b/bitbake/lib/toaster/toastergui/templates/projectbuilds.html
index 02d166341f..afcf5191b5 100644
--- a/bitbake/lib/toaster/toastergui/templates/projectbuilds.html
+++ b/bitbake/lib/toaster/toastergui/templates/projectbuilds.html
@@ -49,7 +49,14 @@
49 <!-- Table data rows; the order needs to match the order of "tablecols" definitions; and the <td class value needs to match the tablecols clclass value for show/hide buttons to work --> 49 <!-- Table data rows; the order needs to match the order of "tablecols" definitions; and the <td class value needs to match the tablecols clclass value for show/hide buttons to work -->
50 {% for br in objects %}{% if br.build %} {% with build=br.build %} {# if we have a build, just display it #} 50 {% for br in objects %}{% if br.build %} {% with build=br.build %} {# if we have a build, just display it #}
51 <tr class="data"> 51 <tr class="data">
52 <td class="outcome"><a href="{% url "builddashboard" build.id %}">{%if build.outcome == build.SUCCEEDED%}<i class="icon-ok-sign success"></i>{%elif build.outcome == build.FAILED%}<i class="icon-minus-sign error"></i>{%else%}{%endif%}</a></td> 52 <td class="outcome"><a href="{% url "builddashboard" build.id %}">{%if build.outcome == build.SUCCEEDED%}<i class="icon-ok-sign success"></i>{%elif build.outcome == build.FAILED%}<i class="icon-minus-sign error"></i>{%else%}{%endif%}</a>
53 {% if build.project %}
54 &nbsp; <a href="{% url 'build_artifact' build.id "cookerlog" build.id %}">
55 <i class="icon-download-alt" title="" data-original-title="Download build log"></i>
56 </a>
57 {% endif %}
58 </td>
59
53 <td class="target">{% for t in build.target_set.all %} <a href="{% url "builddashboard" build.id %}"> {{t.target}} </a> <br />{% endfor %}</td> 60 <td class="target">{% for t in build.target_set.all %} <a href="{% url "builddashboard" build.id %}"> {{t.target}} </a> <br />{% endfor %}</td>
54 <td class="machine"><a href="{% url "builddashboard" build.id %}">{{build.machine}}</a></td> 61 <td class="machine"><a href="{% url "builddashboard" build.id %}">{{build.machine}}</a></td>
55 <td class="started_on"><a href="{% url "builddashboard" build.id %}">{{build.started_on|date:"d/m/y H:i"}}</a></td> 62 <td class="started_on"><a href="{% url "builddashboard" build.id %}">{{build.started_on|date:"d/m/y H:i"}}</a></td>
@@ -70,11 +77,6 @@
70 <td class="errors_no"> 77 <td class="errors_no">
71 {% if build.errors_no %} 78 {% if build.errors_no %}
72 <a class="errors_no error" href="{% url "builddashboard" build.id %}#errors">{{build.errors_no}} error{{build.errors_no|pluralize}}</a> 79 <a class="errors_no error" href="{% url "builddashboard" build.id %}#errors">{{build.errors_no}} error{{build.errors_no|pluralize}}</a>
73 {% if MANAGED and build.project %}
74 <a href="{% url 'build_artifact' build.id "cookerlog" build.id %}">
75 <i class="icon-download-alt" title="" data-original-title="Download build log"></i>
76 </a>
77 {% endif %}
78 {%endif%} 80 {%endif%}
79 </td> 81 </td>
80 <td class="warnings_no">{% if build.warnings_no %}<a class="warnings_no warning" href="{% url "builddashboard" build.id %}#warnings">{{build.warnings_no}} warning{{build.warnings_no|pluralize}}</a>{%endif%}</td> 82 <td class="warnings_no">{% if build.warnings_no %}<a class="warnings_no warning" href="{% url "builddashboard" build.id %}#warnings">{{build.warnings_no}} warning{{build.warnings_no|pluralize}}</a>{%endif%}</td>
diff --git a/bitbake/lib/toaster/toastergui/templates/unavailable_artifact.html b/bitbake/lib/toaster/toastergui/templates/unavailable_artifact.html
new file mode 100644
index 0000000000..c93d4257db
--- /dev/null
+++ b/bitbake/lib/toaster/toastergui/templates/unavailable_artifact.html
@@ -0,0 +1,17 @@
1{% extends "base.html" %}
2{% load projecttags %}
3{% load humanize %}
4{% load static %}
5
6{% block pagecontent %}
7<div class="section">
8</div>
9<div class="row-fluid">
10
11 <div class="alert alert-info">
12 <p class="lead"> The artifact you are seeking to download is not available. We are sorry. You can <a href="javascript:window.history.back()">go back</a>
13 </p>
14 </div>
15</div>
16{% endblock %}
17
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py
index b5ff9b1d53..eb323ec81d 100755
--- a/bitbake/lib/toaster/toastergui/views.py
+++ b/bitbake/lib/toaster/toastergui/views.py
@@ -2914,9 +2914,6 @@ if toastermain.settings.MANAGED:
2914 if artifact_type == "imagefile": 2914 if artifact_type == "imagefile":
2915 file_name = Target_Image_File.objects.get(target__build = b, pk = artifact_id).file_name 2915 file_name = Target_Image_File.objects.get(target__build = b, pk = artifact_id).file_name
2916 2916
2917 elif artifact_type == "cookerlog":
2918 file_name = b.cooker_log_path
2919
2920 elif artifact_type == "buildartifact": 2917 elif artifact_type == "buildartifact":
2921 file_name = BuildArtifact.objects.get(build = b, pk = artifact_id).file_name 2918 file_name = BuildArtifact.objects.get(build = b, pk = artifact_id).file_name
2922 2919
@@ -2935,26 +2932,87 @@ if toastermain.settings.MANAGED:
2935 2932
2936 2933
2937 def build_artifact(request, build_id, artifact_type, artifact_id): 2934 def build_artifact(request, build_id, artifact_type, artifact_id):
2938 b = Build.objects.get(pk=build_id) 2935 if artifact_type in ["cookerlog"]:
2939 if b.buildrequest is None or b.buildrequest.environment is None: 2936 # these artifacts are saved after building, so they are on the server itself
2940 raise Exception("Artifact not available for download (missing build request or build environment)") 2937 def _mimetype_for_artifact(path):
2938 try:
2939 import magic
2940
2941 # fair warning: this is a mess; there are multiple competing and incompatible
2942 # magic modules floating around, so we try some of the most common combinations
2943
2944 try: # we try ubuntu's python-magic 5.4
2945 m = magic.open(magic.MAGIC_MIME_TYPE)
2946 m.load()
2947 return m.file(path)
2948 except AttributeError:
2949 pass
2950
2951 try: # we try python-magic 0.4.6
2952 m = magic.Magic(magic.MAGIC_MIME)
2953 return m.from_file(path)
2954 except AttributeError:
2955 pass
2956
2957 try: # we try pip filemagic 1.6
2958 m = magic.Magic(flags=magic.MAGIC_MIME_TYPE)
2959 return m.id_filename(path)
2960 except AttributeError:
2961 pass
2962
2963 return "binary/octet-stream"
2964 except ImportError:
2965 return "binary/octet-stream"
2966 try:
2967 # match code with runbuilds.Command.archive()
2968 build_artifact_storage_dir = os.path.join(ToasterSetting.objects.get(name="ARTIFACTS_STORAGE_DIR").value, "%d" % int(build_id))
2969 file_name = os.path.join(build_artifact_storage_dir, "cooker_log.txt")
2970
2971 fsock = open(file_name, "r")
2972 content_type=_mimetype_for_artifact(file_name)
2941 2973
2942 file_name = _file_name_for_artifact(b, artifact_type, artifact_id) 2974 response = HttpResponse(fsock, content_type = content_type)
2943 fsock = None 2975
2944 content_type='application/force-download' 2976 response['Content-Disposition'] = 'attachment; filename=' + os.path.basename(file_name)
2977 return response
2978 except IOError:
2979 context = {
2980 'build' : Build.objects.get(pk = build_id),
2981 }
2982 return render(request, "unavailable_artifact.html", context)
2945 2983
2946 if file_name is None:
2947 raise Exception("Could not handle artifact %s id %s" % (artifact_type, artifact_id))
2948 else: 2984 else:
2949 content_type = b.buildrequest.environment.get_artifact_type(file_name) 2985 # retrieve the artifact directly from the build environment
2950 fsock = b.buildrequest.environment.get_artifact(file_name) 2986 return _get_be_artifact(request, build_id, artifact_type, artifact_id)
2951 file_name = os.path.basename(file_name) # we assume that the build environment system has the same path conventions as host
2952 2987
2953 response = HttpResponse(fsock, content_type = content_type)
2954 2988
2955 # returns a file from the environment 2989 def _get_be_artifact(request, build_id, artifact_type, artifact_id):
2956 response['Content-Disposition'] = 'attachment; filename=' + file_name 2990 try:
2957 return response 2991 b = Build.objects.get(pk=build_id)
2992 if b.buildrequest is None or b.buildrequest.environment is None:
2993 raise Exception("Artifact not available for download (missing build request or build environment)")
2994
2995 file_name = _file_name_for_artifact(b, artifact_type, artifact_id)
2996 fsock = None
2997 content_type='application/force-download'
2998
2999 if file_name is None:
3000 raise Exception("Could not handle artifact %s id %s" % (artifact_type, artifact_id))
3001 else:
3002 content_type = b.buildrequest.environment.get_artifact_type(file_name)
3003 fsock = b.buildrequest.environment.get_artifact(file_name)
3004 file_name = os.path.basename(file_name) # we assume that the build environment system has the same path conventions as host
3005
3006 response = HttpResponse(fsock, content_type = content_type)
3007
3008 # returns a file from the environment
3009 response['Content-Disposition'] = 'attachment; filename=' + file_name
3010 return response
3011 except IOError:
3012 context = {
3013 'build' : Build.objects.get(pk = build_id),
3014 }
3015 return render(request, "unavailable_artifact.html", context)
2958 3016
2959 3017
2960 3018