summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexandru DAMIAN <alexandru.damian@intel.com>2014-12-05 15:19:55 +0000
committerRichard Purdie <richard.purdie@linuxfoundation.org>2014-12-18 10:24:06 +0000
commitaa9816ad79ca34000c1cb0cdc4d35b5fc09a9ba3 (patch)
tree0c902d4bdf2bab05b1740c63cbe3735707b5394f
parent85a17f86ea2edf24b54aa62bd25e10ff522cb6e7 (diff)
downloadpoky-aa9816ad79ca34000c1cb0cdc4d35b5fc09a9ba3.tar.gz
bitbake: toastergui: implement UI changes to allow file download
This patchset adds download links in the build analisys pages if toaster runs in managed mode. This allows the user to access data directly from the web interface. [YOCTO #6837] (Bitbake rev: 6000e1ae5c846e51932ecd0dc21e0fa02eb10357) Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--bitbake/lib/toaster/toastergui/templates/base.html18
-rw-r--r--bitbake/lib/toaster/toastergui/templates/build.html29
-rw-r--r--bitbake/lib/toaster/toastergui/templates/builddashboard.html131
-rw-r--r--bitbake/lib/toaster/toastergui/templates/configuration.html6
-rw-r--r--bitbake/lib/toaster/toastergui/templates/package_detail_base.html3
-rw-r--r--bitbake/lib/toaster/toastergui/templates/recipe.html11
-rw-r--r--bitbake/lib/toaster/toastergui/templates/recipes.html7
-rw-r--r--bitbake/lib/toaster/toastergui/templates/target.html8
-rw-r--r--bitbake/lib/toaster/toastergui/templates/task.html18
-rw-r--r--bitbake/lib/toaster/toastergui/templates/tasks.html12
-rwxr-xr-xbitbake/lib/toaster/toastergui/views.py168
11 files changed, 276 insertions, 135 deletions
diff --git a/bitbake/lib/toaster/toastergui/templates/base.html b/bitbake/lib/toaster/toastergui/templates/base.html
index 594c495bd3..bc7a0ee436 100644
--- a/bitbake/lib/toaster/toastergui/templates/base.html
+++ b/bitbake/lib/toaster/toastergui/templates/base.html
@@ -3,14 +3,14 @@
3<html lang="en"> 3<html lang="en">
4 <head> 4 <head>
5 <title>{% if objectname %} {{objectname|title}} - {% endif %}Toaster</title> 5 <title>{% if objectname %} {{objectname|title}} - {% endif %}Toaster</title>
6<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}" type="text/css"> 6<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}" type="text/css"/>
7<link rel="stylesheet" href="{% static 'css/bootstrap-responsive.min.css' %}" type='text/css'> 7<link rel="stylesheet" href="{% static 'css/bootstrap-responsive.min.css' %}" type='text/css'/>
8<link rel="stylesheet" href="{% static 'css/font-awesome.min.css' %}" type='text/css'> 8<link rel="stylesheet" href="{% static 'css/font-awesome.min.css' %}" type='text/css'/>
9<link rel="stylesheet" href="{% static 'css/prettify.css' %}" type='text/css'> 9<link rel="stylesheet" href="{% static 'css/prettify.css' %}" type='text/css'/>
10<link rel="stylesheet" href="{% static 'css/default.css' %}" type='text/css'> 10<link rel="stylesheet" href="{% static 'css/default.css' %}" type='text/css'/>
11 11
12<meta name="viewport" content="width=device-width, initial-scale=1.0" /> 12<meta name="viewport" content="width=device-width, initial-scale=1.0" />
13<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> 13<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
14<script src="{% static 'js/jquery-2.0.3.min.js' %}"> 14<script src="{% static 'js/jquery-2.0.3.min.js' %}">
15</script> 15</script>
16<script src="{% static 'js/jquery.cookie.js' %}"> 16<script src="{% static 'js/jquery.cookie.js' %}">
@@ -64,7 +64,7 @@
64 </div> 64 </div>
65 <!-- New build popover --> 65 <!-- New build popover -->
66 <div class="btn-group pull-right" id="new-build-button"> 66 <div class="btn-group pull-right" id="new-build-button">
67 <button class="btn dropdown-toggle" data-toggle="dropdown" href="#"> 67 <button class="btn dropdown-toggle" data-toggle="dropdown">
68 New build 68 New build
69 <i class="icon-caret-down"></i> 69 <i class="icon-caret-down"></i>
70 </button> 70 </button>
@@ -78,7 +78,7 @@
78 </span> 78 </span>
79 <form id="change-project-form" style="display:none;"> 79 <form id="change-project-form" style="display:none;">
80 <div class="input-append"> 80 <div class="input-append">
81 <input type="text" class="input-medium" id="project-name-input" placeholder="Type a project name" autocomplete="off" data-minLength="1" data-autocomplete="off" data-provide="typeahead"> 81 <input type="text" class="input-medium" id="project-name-input" placeholder="Type a project name" autocomplete="off" data-minLength="1" data-autocomplete="off" data-provide="typeahead"/>
82 <button id="save-project-button" class="btn" type="button">Save</button> 82 <button id="save-project-button" class="btn" type="button">Save</button>
83 <a href="#" id="cancel-change-project" class="btn btn-link">Cancel</a> 83 <a href="#" id="cancel-change-project" class="btn btn-link">Cancel</a>
84 </div> 84 </div>
@@ -92,7 +92,7 @@
92 <li id="targets-form"> 92 <li id="targets-form">
93 <h6>Target(s):</h6> 93 <h6>Target(s):</h6>
94 <form> 94 <form>
95 <input type="text" class="input-xlarge" id="build-target-input" placeholder="Type a target name" autocomplete="off" data-minLength="1" data-autocomplete="off" data-provide="typeahead" > 95 <input type="text" class="input-xlarge" id="build-target-input" placeholder="Type a target name" autocomplete="off" data-minLength="1" data-autocomplete="off" data-provide="typeahead" />
96 <div> 96 <div>
97 <a class="btn btn-primary" id="build-button" disabled="disabled" data-project-id="{{project.id}}">Build</a> 97 <a class="btn btn-primary" id="build-button" disabled="disabled" data-project-id="{{project.id}}">Build</a>
98 </div> 98 </div>
diff --git a/bitbake/lib/toaster/toastergui/templates/build.html b/bitbake/lib/toaster/toastergui/templates/build.html
index f20f041749..e71e38feb9 100644
--- a/bitbake/lib/toaster/toastergui/templates/build.html
+++ b/bitbake/lib/toaster/toastergui/templates/build.html
@@ -45,11 +45,34 @@
45 <td class="machine"><a href="{% url "builddashboard" build.id %}">{{build.machine}}</a></td> 45 <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> 46 <td class="started_on"><a href="{% url "builddashboard" build.id %}">{{build.started_on|date:"d/m/y H:i"}}</a></td>
47 <td class="completed_on"><a href="{% url "builddashboard" build.id %}">{{build.completed_on|date:"d/m/y H:i"}}</a></td> 47 <td class="completed_on"><a href="{% url "builddashboard" build.id %}">{{build.completed_on|date:"d/m/y H:i"}}</a></td>
48 <td class="failed_tasks error">{% query build.task_build outcome=4 order__gt=0 as exectask%}{% if exectask.count == 1 %}<a href="{% url "task" build.id exectask.0.id %}">{{exectask.0.recipe.name}}.{{exectask.0.task_name}}</a>{% elif exectask.count > 1%}<a href="{% url "tasks" build.id %}?filter=outcome%3A4">{{exectask.count}}</a>{%endif%}</td> 48 <td class="failed_tasks error">
49 <td class="errors_no">{% if build.errors_no %}<a class="errors_no error" href="{% url "builddashboard" build.id %}#errors">{{build.errors_no}} error{{build.errors_no|pluralize}}</a>{%endif%}</td> 49 {% query build.task_build outcome=4 order__gt=0 as exectask%}
50 {% if exectask.count == 1 %}
51 <a href="{% url "task" build.id exectask.0.id %}">{{exectask.0.recipe.name}}.{{exectask.0.task_name}}</a>
52 {% if MANAGED and build.project %}
53 <a href="{% url 'build_artifact' build.id "tasklogfile" exectask.0.id %}">
54 <i class="icon-download-alt" title="" data-original-title="Download task log file"></i>
55 </a>
56 {% endif %}
57 {% elif exectask.count > 1%}
58 <a href="{% url "tasks" build.id %}?filter=outcome%3A4">{{exectask.count}} task{{exectask.count|pluralize}}</a>
59 {%endif%}
60 </td>
61 <td class="errors_no">
62 {% 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>
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%}
70 </td>
50 <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> 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>
51 <td class="time"><a href="{% url "buildtime" build.id %}">{{build.timespent|sectohms}}</a></td> 72 <td class="time"><a href="{% url "buildtime" build.id %}">{{build.timespent|sectohms}}</a></td>
52 <td class="log">{{build.cooker_log_path}}</td> 73 {% if not MANAGED or not build.project %}
74 <td class="log">{{build.cooker_log_path}}</td>
75 {% endif %}
53 <td class="output"> 76 <td class="output">
54 {% if build.outcome == build.SUCCEEDED %} 77 {% if build.outcome == build.SUCCEEDED %}
55 <a href="{%url "builddashboard" build.id%}#images">{{fstypes|get_dict_value:build.id}}</a> 78 <a href="{%url "builddashboard" build.id%}#images">{{fstypes|get_dict_value:build.id}}</a>
diff --git a/bitbake/lib/toaster/toastergui/templates/builddashboard.html b/bitbake/lib/toaster/toastergui/templates/builddashboard.html
index e682094305..2458cdb6d1 100644
--- a/bitbake/lib/toaster/toastergui/templates/builddashboard.html
+++ b/bitbake/lib/toaster/toastergui/templates/builddashboard.html
@@ -42,9 +42,9 @@
42 {% if build.toaster_exceptions.count > 0 %} 42 {% if build.toaster_exceptions.count > 0 %}
43 <div class="row"> 43 <div class="row">
44 <small class="pull-right"> 44 <small class="pull-right">
45 <i class="icon-question-sign get-help get-help-blue" title="" data-original-title="Toaster exceptions do not affect your build: only the operation of Toaster"></i> 45 <i class="icon-question-sign get-help get-help-blue" title="" data-original-title="Toaster exceptions do not affect your build: only the operation of Toaster"></i>
46 <a class="show-exceptions" href="#exceptions">Toaster threw {{build.toaster_exceptions.count}} exception{{build.toaster_exceptions.count|pluralize}}</a> 46 <a class="show-exceptions" href="#exceptions">Toaster threw {{build.toaster_exceptions.count}} exception{{build.toaster_exceptions.count|pluralize}}</a>
47 </small> 47 </small>
48 </div> 48 </div>
49 {% endif %} 49 {% endif %}
50 </div> 50 </div>
@@ -54,6 +54,9 @@
54<div class="accordion span10 pull-right" id="errors"> 54<div class="accordion span10 pull-right" id="errors">
55 <div class="accordion-group"> 55 <div class="accordion-group">
56 <div class="accordion-heading"> 56 <div class="accordion-heading">
57 {% if MANAGED and build.project %}
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 %}
57 <a class="accordion-toggle error toggle-errors"> 60 <a class="accordion-toggle error toggle-errors">
58 <h2 id="error-toggle"> 61 <h2 id="error-toggle">
59 <i class="icon-minus-sign"></i> 62 <i class="icon-minus-sign"></i>
@@ -66,13 +69,10 @@
66 <div class="span10"> 69 <div class="span10">
67 {% for error in logmessages %}{% if error.level == 2 %} 70 {% for error in logmessages %}{% if error.level == 2 %}
68 <div class="alert alert-error"> 71 <div class="alert alert-error">
69 {% if MANAGED and error.pathname %}
70 <pre><a href="{% url 'build_artifact' build.pk 'logmessagefile' error.pk %}" target="_blanc">{{error.message}}</pre>
71 {% else %}
72 <pre>{{error.message}}</pre> 72 <pre>{{error.message}}</pre>
73 {% endif %}
74 </div> 73 </div>
75 {% endif %}{% endfor %} 74 {% endif %}
75 {% endfor %}
76 </div> 76 </div>
77 </div> 77 </div>
78 </div> 78 </div>
@@ -84,21 +84,21 @@
84<!-- built images --> 84<!-- built images -->
85{% if hasImages %} 85{% if hasImages %}
86<div class="row-fluid span10 pull-right"> 86<div class="row-fluid span10 pull-right">
87 <h2>Images</h2> 87 <h2>Images</h2>
88 {% for target in targets %} 88 {% for target in targets %}
89 {% if target.target.is_image %} 89 {% if target.target.is_image %}
90 <div class="well dashboard-section"> 90 <div class="well dashboard-section">
91 <h3><a href="{% url 'target' build.pk target.target.pk %}">{{target.target}}</a> 91 <h3><a href="{% url 'target' build.pk target.target.pk %}">{{target.target}}</a>
92 </h3> 92 </h3>
93 <dl class="dl-horizontal"> 93 <dl class="dl-horizontal">
94 <dt>Packages included</dt> 94 <dt>Packages included</dt>
95 <dd><a href="{% url 'target' build.pk target.target.pk %}">{{target.npkg}}</a></dd> 95 <dd><a href="{% url 'target' build.pk target.target.pk %}">{{target.npkg}}</a></dd>
96 <dt>Total package size</dt> 96 <dt>Total package size</dt>
97 <dd>{{target.pkgsz|filtered_filesizeformat}}</dd> 97 <dd>{{target.pkgsz|filtered_filesizeformat}}</dd>
98 {% if target.targetHasNoImages %} 98 {% if target.targetHasNoImages %}
99 </dl> 99 </dl>
100 <div class="row-fluid"> 100 <div class="row-fluid">
101 <div class="alert alert-info span7"> 101 <div class="alert alert-info span7">
102 <p> 102 <p>
103 <b>This build did not create any image files</b> 103 <b>This build did not create any image files</b>
104 </p> 104 </p>
@@ -111,30 +111,45 @@
111 license manifest information</a> in Toaster. 111 license manifest information</a> in Toaster.
112 </p> 112 </p>
113 </div> 113 </div>
114 </div> 114 </div>
115 {% else %} 115 {% else %}
116 <dt> 116 <dt>
117 <i class="icon-question-sign get-help" title="The location in disk of the license manifest, a document listing all packages installed in your image and their licenses"></i> 117 <i class="icon-question-sign get-help" title="The location in disk of the license manifest, a document listing all packages installed in your image and their licenses"></i>
118 <a href="{% url 'targetpkg' build.pk target.target.pk %}">License manifest</a> 118
119 </dt> 119 {% if MANAGED and build.project %}
120 <dd><code>{{target.target.license_manifest_path}}</code></dd> 120 License manifest
121 <dt> 121 {% else %}
122 <i class="icon-question-sign get-help" title="Image files are stored in <code>/build/tmp/deploy/images/</code>"></i> 122 <a href="{% url 'targetpkg' build.pk target.target.pk %}">License manifest</a>
123 Image files 123 {% endif %}
124 </dt> 124 </dt>
125 <dd> 125 {% if MANAGED and build.project %}
126 <ul> 126 <dd>
127 <a href="{% url 'targetpkg' build.pk target.target.pk %}">View in Toaster</a> |
128 <a href="{% url 'build_artifact' build.pk 'licensemanifest' target.target.pk %}">Download</a></dd>
129 {% else %}
130 <dd><code>{{target.target.license_manifest_path}}</code></dd>
131 {% endif %}
132 <dt>
133 <i class="icon-question-sign get-help" title="Image files are stored in <code>/build/tmp/deploy/images/</code>"></i>
134 Image files
135 </dt>
136 <dd>
137 <ul>
127 {% for i in target.imageFiles %} 138 {% for i in target.imageFiles %}
128 <li>{{i.path}} 139 {% if build.project %}
129 ({{i.size|filtered_filesizeformat}})</li> 140 <li><a href="{% url 'build_artifact' build.pk 'imagefile' i.id %}">{{i.path}}</a>
141 {% else %}
142 <li>{{i.path}}
143 {% endif %}
144 ({{i.size|filtered_filesizeformat}})</li>
130 {% endfor %} 145 {% endfor %}
131 </ul> 146 </ul>
132 </dd> 147 </dd>
133 </dl> 148 </dl>
134 {% endif %} 149 {% endif %}
135 </div> 150 </div>
136 {% endif %} 151 {% endif %}
137 {% endfor %} 152 {% endfor %}
138</div> 153</div>
139{% endif %} 154{% endif %}
140 155
@@ -142,6 +157,35 @@
142<!-- error dump --> 157<!-- error dump -->
143{%endif%} 158{%endif%}
144 159
160<!-- other artifacts -->
161{% if build.buildartifact_set.all.count > 0 %}
162<div class="row-fluid span10 pull-right">
163<h2>Other artifacts</h2>
164
165 <div class="well dashboard-section">
166 <dl class="dl-horizontal">
167 <dt>
168 <i class="icon-question-sign get-help" title="Build artifacts discovered in <i>tmp/deploy/images</i>. Usually kernel images and kernel modules."></i>
169 Other artifacts</dt>
170 <dd><div>
171 {% for ba in build.buildartifact_set.all|dictsort:"file_name" %}
172 {% if MANAGED and build.project %}
173 <a href="{%url 'build_artifact' build.id 'buildartifact' ba.id %}">
174 {% endif %}
175 {{ba.get_local_file_name}}
176 {% if MANAGED and build.project %}
177 </a>
178 {% endif %}
179
180 ({{ba.file_size|filtered_filesizeformat}}) <br/>
181 {% endfor %}
182 </div>
183 </dd>
184
185 </div>
186
187</div>
188{% endif %}
145<!-- build summary --> 189<!-- build summary -->
146<div class="row-fluid span10 pull-right"> 190<div class="row-fluid span10 pull-right">
147<h2>Build summary</h2> 191<h2>Build summary</h2>
@@ -158,12 +202,19 @@
158 <dl> 202 <dl>
159 {% query build.task_build outcome=4 order__gt=0 as exectask%} 203 {% query build.task_build outcome=4 order__gt=0 as exectask%}
160 {% if exectask.count > 0 %} 204 {% if exectask.count > 0 %}
161 <dt>Failed tasks</td> 205 <dt>Failed tasks</dt>
162 <dd> 206 <dd>
163 {% if exectask.count == 1 %} 207 {% if exectask.count == 1 %}
164 <a class="error" href="{% url "task" build.id exectask.0.id %}"> 208 <a class="error" href="{% url "task" build.id exectask.0.id %}">
165 {{exectask.0.recipe.name}} 209 {{exectask.0.recipe.name}}
166 <span class="task-name">{{exectask.0.task_name}}</span> 210 <span class="task-name">{{exectask.0.task_name}}</span>
211
212 {% if MANAGED and build.project %}
213 <a href="{% url 'build_artifact' build.id "tasklogfile" exectask.0.id %}">
214 <i class="icon-download-alt" title="" data-original-title="Download task log file"></i>
215 </a>
216 {% endif %}
217
167 </a> 218 </a>
168 {% elif exectask.count > 1%} 219 {% elif exectask.count > 1%}
169 <a class="error" href="{% url "tasks" build.id %}?filter=outcome%3A4">{{exectask.count}}</a> 220 <a class="error" href="{% url "tasks" build.id %}?filter=outcome%3A4">{{exectask.count}}</a>
diff --git a/bitbake/lib/toaster/toastergui/templates/configuration.html b/bitbake/lib/toaster/toastergui/templates/configuration.html
index 49a6a89d5c..d3b34a2096 100644
--- a/bitbake/lib/toaster/toastergui/templates/configuration.html
+++ b/bitbake/lib/toaster/toastergui/templates/configuration.html
@@ -50,7 +50,9 @@
50 <th>Layer</th> 50 <th>Layer</th>
51 <th>Layer branch</th> 51 <th>Layer branch</th>
52 <th>Layer commit</th> 52 <th>Layer commit</th>
53 <th>Layer directory</th> 53 {% if not MANAGED or not build.project %}
54 <th>Layer directory</th>
55 {% endif %}
54 </tr> 56 </tr>
55 </thead> 57 </thead>
56 <tbody>{% for lv in build.layer_version_build.all|dictsort:"layer.name" %} 58 <tbody>{% for lv in build.layer_version_build.all|dictsort:"layer.name" %}
@@ -61,7 +63,9 @@
61 <li>{{lv.commit}}</li> </ul>"> 63 <li>{{lv.commit}}</li> </ul>">
62 {{lv.commit|truncatechars:13}} 64 {{lv.commit|truncatechars:13}}
63 </a></td> 65 </a></td>
66 {% if not MANAGED or not build.project %}
64 <td>{{lv.layer.local_path}}</td> 67 <td>{{lv.layer.local_path}}</td>
68 {% endif %}
65 </tr>{% endfor %} 69 </tr>{% endfor %}
66 </tbody> 70 </tbody>
67 </table> 71 </table>
diff --git a/bitbake/lib/toaster/toastergui/templates/package_detail_base.html b/bitbake/lib/toaster/toastergui/templates/package_detail_base.html
index cd015d3555..dfeba55058 100644
--- a/bitbake/lib/toaster/toastergui/templates/package_detail_base.html
+++ b/bitbake/lib/toaster/toastergui/templates/package_detail_base.html
@@ -135,11 +135,14 @@
135 </dt> 135 </dt>
136 136
137 <dd class="iscommit">{{package.recipe.layer_version.commit}}</dd> 137 <dd class="iscommit">{{package.recipe.layer_version.commit}}</dd>
138
139 {% if not MANAGED or not build.project %}
138 <dt> 140 <dt>
139 Layer directory 141 Layer directory
140 <i class="icon-question-sign get-help" title="Path to the layer providing the recipe that builds this package"></i> 142 <i class="icon-question-sign get-help" title="Path to the layer providing the recipe that builds this package"></i>
141 </dt> 143 </dt>
142 <dd><code>{{package.recipe.layer_version.layer.local_path}}</code></dd> 144 <dd><code>{{package.recipe.layer_version.layer.local_path}}</code></dd>
145 {% endif %}
143 </dl> 146 </dl>
144 </div> <!-- row4 well --> 147 </div> <!-- row4 well -->
145 {% endblock twocolumns %} 148 {% endblock twocolumns %}
diff --git a/bitbake/lib/toaster/toastergui/templates/recipe.html b/bitbake/lib/toaster/toastergui/templates/recipe.html
index a830ba9fb8..b20c65e3c8 100644
--- a/bitbake/lib/toaster/toastergui/templates/recipe.html
+++ b/bitbake/lib/toaster/toastergui/templates/recipe.html
@@ -52,16 +52,19 @@
52 Layer 52 Layer
53 </dt> 53 </dt>
54 <dd>{{layer.name}}</dd> 54 <dd>{{layer.name}}</dd>
55
56 {% if not MANAGED or not build.project %}
55 <dt> 57 <dt>
56 <i class="icon-question-sign get-help" title="Path to the layer providing the recipe"></i> 58 <i class="icon-question-sign get-help" title="Path to the layer providing the recipe"></i>
57 Layer directory 59 Layer directory
58 </dt> 60 </dt>
59 <dd><code>{{layer.local_path}}</code></dd> 61 <dd><code>{{layer.local_path}}</code></dd>
62 {% endif %}
60 <dt> 63 <dt>
61 <i class="icon-question-sign get-help" title="Path to the recipe .bb file"></i> 64 <i class="icon-question-sign get-help" title="Path to the recipe .bb file"></i>
62 Recipe file 65 Recipe file
63 </dt> 66 </dt>
64 <dd><code>{{object.file_path}}</code></dd> 67 <dd><code>{{object.get_local_path}}</code></dd>
65 {% if layer_version.branch %} 68 {% if layer_version.branch %}
66 <dt> 69 <dt>
67 <i class="icon-question-sign get-help" title="The Git branch of the layer providing the recipe"></i> 70 <i class="icon-question-sign get-help" title="The Git branch of the layer providing the recipe"></i>
@@ -126,6 +129,12 @@
126 <td> 129 <td>
127 {% ifnotequal task.sstate_result task.SSTATE_NA %} 130 {% ifnotequal task.sstate_result task.SSTATE_NA %}
128 <a {{ task|task_color }} href="{% url "task" build.pk task.pk %}">{{task.get_sstate_result_display}}</a> 131 <a {{ task|task_color }} href="{% url "task" build.pk task.pk %}">{{task.get_sstate_result_display}}</a>
132 {% if MANAGED and build.project and task.outcome = task.OUTCOME_FAILED %}
133 <a href="{% url 'build_artifact' build.pk "tasklogfile" task.pk %}">
134 <i class="icon-download-alt" title="" data-original-title="Download task log file"></i>
135 </a>
136 {% endif %}
137
129 {% endifnotequal %} 138 {% endifnotequal %}
130 </td> 139 </td>
131 140
diff --git a/bitbake/lib/toaster/toastergui/templates/recipes.html b/bitbake/lib/toaster/toastergui/templates/recipes.html
index 791a487a81..889e676b45 100644
--- a/bitbake/lib/toaster/toastergui/templates/recipes.html
+++ b/bitbake/lib/toaster/toastergui/templates/recipes.html
@@ -98,8 +98,11 @@
98 {{recipe.layer_version.commit|truncatechars:13}} 98 {{recipe.layer_version.commit|truncatechars:13}}
99 </a> 99 </a>
100 </td> 100 </td>
101 <!-- Layer directory --> 101
102 <td class="layer_version__layer__local_path">{{recipe.layer_version.layer.local_path}}</td> 102 {% if not MANAGED or not build.project %}
103 <!-- Layer directory -->
104 <td class="layer_version__layer__local_path">{{recipe.layer_version.layer.local_path}}</td>
105 {% endif %}
103 </tr> 106 </tr>
104 107
105 {% endfor %} 108 {% endfor %}
diff --git a/bitbake/lib/toaster/toastergui/templates/target.html b/bitbake/lib/toaster/toastergui/templates/target.html
index c879c39d5a..1309b52dad 100644
--- a/bitbake/lib/toaster/toastergui/templates/target.html
+++ b/bitbake/lib/toaster/toastergui/templates/target.html
@@ -152,9 +152,11 @@
152 {{package.recipe.layer_version.commit|truncatechars:13}} 152 {{package.recipe.layer_version.commit|truncatechars:13}}
153 </a> 153 </a>
154 </td> 154 </td>
155 <td class="layer_directory"> 155 {% if not MANAGED or not build.project %}
156 {{ package.recipe.layer_version.layer.local_path }} 156 <td class="layer_directory">
157 </td> 157 {{ package.recipe.layer_version.layer.local_path }}
158 </td>
159 {% endif %}
158 </tr> 160 </tr>
159 {% endfor %} 161 {% endfor %}
160 162
diff --git a/bitbake/lib/toaster/toastergui/templates/task.html b/bitbake/lib/toaster/toastergui/templates/task.html
index 1b270420db..09fd25b259 100644
--- a/bitbake/lib/toaster/toastergui/templates/task.html
+++ b/bitbake/lib/toaster/toastergui/templates/task.html
@@ -24,17 +24,17 @@
24 {# executed tasks outcome #} 24 {# executed tasks outcome #}
25 <dl class="dl-horizontal"> 25 <dl class="dl-horizontal">
26 {% if task.logfile %} 26 {% if task.logfile %}
27 {% if MANAGED and build.project %}
28 <a class="btn btn-large" href="{% url 'build_artifact' build.id "tasklogfile" task.pk %}" style="margin:15px;">Download task log</a>
29 {% else %}
27 <dt> 30 <dt>
28 <i class="icon-question-sign get-help" title="Path the task log file"></i> Log file 31 <i class="icon-question-sign get-help" title="Path the task log file"></i> Log file
29 </dt> 32 </dt>
30 <dd> 33 <dd>
31 {% if MANAGED %} 34 <code>{{task.logfile}}</code>
32 <code><a href="{% url 'build_artifact' build.pk 'tasklogfile' task.pk %}" target="_blanc">{{task.logfile}}</a></code>
33 {% else %}
34 <code>{{task.logfile}}</code>
35 {% endif %}
36 </dd> 35 </dd>
37 {% endif %} 36 {% endif %}
37 {% endif %}
38 {# show stack trace for failed task #} 38 {# show stack trace for failed task #}
39 {% if task.outcome == task.OUTCOME_FAILED and log_head %} 39 {% if task.outcome == task.OUTCOME_FAILED and log_head %}
40 <h3>Python stack trace</h3> 40 <h3>Python stack trace</h3>
@@ -191,6 +191,9 @@
191 <strong>Failed</strong> to restore output from sstate cache. The file was found but could not be unpacked. 191 <strong>Failed</strong> to restore output from sstate cache. The file was found but could not be unpacked.
192 </div> 192 </div>
193 <dl class="dl-horizontal"> 193 <dl class="dl-horizontal">
194 {% if MANAGED and build.project %}
195 <a href="{% url 'build_artifact' build.id "tasklogfile" task.pk %}" style="margin:15px;">Download log</a>
196 {% else %}
194 <dt> 197 <dt>
195 <i class="icon-question-sign get-help" title="Path to the cache attempt log file"></i> 198 <i class="icon-question-sign get-help" title="Path to the cache attempt log file"></i>
196 Log file 199 Log file
@@ -201,6 +204,7 @@
201 Time (secs) 204 Time (secs)
202 </dt> 205 </dt>
203 <dd>{{task.elapsed_time|format_none_and_zero}}</dd> 206 <dd>{{task.elapsed_time|format_none_and_zero}}</dd>
207 {% endif %}
204 </dl> 208 </dl>
205 <div class="alert alert-info"> 209 <div class="alert alert-info">
206 Running the real task instead. 210 Running the real task instead.
@@ -268,8 +272,8 @@
268 Time (secs) 272 Time (secs)
269 </dt> 273 </dt>
270 <dd>{{task.elapsed_time|format_none_and_zero|floatformat:2}}</dd> 274 <dd>{{task.elapsed_time|format_none_and_zero|floatformat:2}}</dd>
271 {% endif %} 275 {% endif %}
272 {% if task.cpu_usage > 0 %} 276 {% if task.cpu_usage > 0 %}
273 <dt> 277 <dt>
274 <i class="icon-question-sign get-help" title="The percentage of task CPU utilization"></i> 278 <i class="icon-question-sign get-help" title="The percentage of task CPU utilization"></i>
275 CPU usage 279 CPU usage
diff --git a/bitbake/lib/toaster/toastergui/templates/tasks.html b/bitbake/lib/toaster/toastergui/templates/tasks.html
index d0c6f4e326..4cbcc5ed68 100644
--- a/bitbake/lib/toaster/toastergui/templates/tasks.html
+++ b/bitbake/lib/toaster/toastergui/templates/tasks.html
@@ -94,6 +94,11 @@
94 <td class="outcome"> 94 <td class="outcome">
95 <a href="{%url "task" build.pk task.pk%} ">{{task.get_outcome_display}} </a> 95 <a href="{%url "task" build.pk task.pk%} ">{{task.get_outcome_display}} </a>
96 <i class="icon-question-sign get-help hover-help" title="{{task.get_outcome_help}}"></i> 96 <i class="icon-question-sign get-help hover-help" title="{{task.get_outcome_help}}"></i>
97 {% if MANAGED and build.project and task.outcome = task.OUTCOME_FAILED %}
98 <a href="{% url 'build_artifact' build.pk "tasklogfile" task.pk %}">
99 <i class="icon-download-alt" title="" data-original-title="Download task log file"></i>
100 </a>
101 {% endif %}
97 </td> 102 </td>
98 <td class="cache_attempt"> 103 <td class="cache_attempt">
99 <a href="{%url "task" build.pk task.pk%} ">{{task.get_sstate_result_display|format_none_and_zero}}</a> 104 <a href="{%url "task" build.pk task.pk%} ">{{task.get_sstate_result_display|format_none_and_zero}}</a>
@@ -107,9 +112,12 @@
107 <td class="disk_io"> 112 <td class="disk_io">
108 {{task.disk_io|format_none_and_zero}} 113 {{task.disk_io|format_none_and_zero}}
109 </td> 114 </td>
115
116 {% if not MANAGED or not build.project %}
110 <td class="task_log"> 117 <td class="task_log">
111 {{task.logfile}} 118 {{task.logfile}}
112 </td> 119 </td>
120 {% endif %}
113 </tr> 121 </tr>
114 {% endfor %} 122 {% endfor %}
115 123
@@ -124,10 +132,10 @@
124 // enable blue hightlight animation for the order link 132 // enable blue hightlight animation for the order link
125 if (location.href.search('#') > -1) { 133 if (location.href.search('#') > -1) {
126 var task_order = location.href.split('#')[1]; 134 var task_order = location.href.split('#')[1];
127 $("#" + task_order).addClass("highlight"); 135 $("#" + task_order).addClass("highlight");
128 } 136 }
129 }); 137 });
130 138
131</script> 139</script>
132 140
133{% endblock %} 141{% endblock %}
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py
index 8301f6ce66..736de784a3 100755
--- a/bitbake/lib/toaster/toastergui/views.py
+++ b/bitbake/lib/toaster/toastergui/views.py
@@ -27,7 +27,7 @@ from django.db import IntegrityError
27from django.shortcuts import render, redirect 27from django.shortcuts import render, redirect
28from orm.models import Build, Target, Task, Layer, Layer_Version, Recipe, LogMessage, Variable 28from orm.models import Build, Target, Task, Layer, Layer_Version, Recipe, LogMessage, Variable
29from orm.models import Task_Dependency, Recipe_Dependency, Package, Package_File, Package_Dependency 29from orm.models import Task_Dependency, Recipe_Dependency, Package, Package_File, Package_Dependency
30from orm.models import Target_Installed_Package, Target_File, Target_Image_File 30from orm.models import Target_Installed_Package, Target_File, Target_Image_File, BuildArtifact
31from django.views.decorators.cache import cache_control 31from django.views.decorators.cache import cache_control
32from django.core.urlresolvers import reverse 32from django.core.urlresolvers import reverse
33from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger 33from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
@@ -421,30 +421,36 @@ def builds(request):
421 'ordericon':_get_toggle_order_icon(request, "timespent"), 421 'ordericon':_get_toggle_order_icon(request, "timespent"),
422 'orderkey' : 'timespent', 422 'orderkey' : 'timespent',
423 }, 423 },
424 {'name': 'Log', 424 {'name': 'Image files', 'clclass': 'output',
425 'qhelp': "The root file system types produced by the build. You can find them in your <code>/build/tmp/deploy/images/</code> directory",
426 # TODO: compute image fstypes from Target_Image_File
427 },
428 ]
429 }
430
431 if not toastermain.settings.MANAGED:
432 context['tablecols'].insert(-2,
433 {'name': 'Log1',
425 'dclass': "span4", 434 'dclass': "span4",
426 'qhelp': "Path to the build main log file", 435 'qhelp': "Path to the build main log file",
427 'clclass': 'log', 'hidden': 1, 436 'clclass': 'log', 'hidden': 1,
428 'orderfield': _get_toggle_order(request, "cooker_log_path"), 437 'orderfield': _get_toggle_order(request, "cooker_log_path"),
429 'ordericon':_get_toggle_order_icon(request, "cooker_log_path"), 438 'ordericon':_get_toggle_order_icon(request, "cooker_log_path"),
430 'orderkey' : 'cooker_log_path', 439 'orderkey' : 'cooker_log_path',
431 }, 440 }
432 {'name': 'Output', 'clclass': 'output', 441 )
433 'qhelp': "The root file system types produced by the build. You can find them in your <code>/build/tmp/deploy/images/</code> directory", 442
434 # TODO: compute image fstypes from Target_Image_File
435 },
436 ]
437 }
438 443
439 if toastermain.settings.MANAGED: 444 if toastermain.settings.MANAGED:
440 context['tablecols'].append( 445 context['tablecols'].append(
441 {'name': 'Project', 'clclass': 'project', 446 {'name': 'Project', 'clclass': 'project',
442 'filter': {'class': 'project', 447 'filter': {'class': 'project',
443 'label': 'Project:', 448 'label': 'Project:',
444 'options': map(lambda x: (x.name,'',x.build_set.filter(outcome__lt=Build.IN_PROGRESS).count()), Project.objects.all()), 449 'options': map(lambda x: (x.name,'',x.build_set.filter(outcome__lt=Build.IN_PROGRESS).count()), Project.objects.all()),
445 450
446 } 451 }
447 }) 452 }
453 )
448 454
449 455
450 response = render(request, template, context) 456 response = render(request, template, context)
@@ -481,12 +487,8 @@ def builddashboard( request, build_id ):
481 hasImages = True 487 hasImages = True
482 npkg = 0 488 npkg = 0
483 pkgsz = 0 489 pkgsz = 0
484 pid= 0
485 tp = Target_Installed_Package.objects.filter( target_id = t.id )
486 package = None 490 package = None
487 for p in tp: 491 for package in Package.objects.filter(id__in = [x.package_id for x in t.target_installed_package_set.all()]):
488 pid = p.package_id
489 package = Package.objects.get( pk = p.package_id )
490 pkgsz = pkgsz + package.size 492 pkgsz = pkgsz + package.size
491 if ( package.installed_name ): 493 if ( package.installed_name ):
492 npkg = npkg + 1 494 npkg = npkg + 1
@@ -499,7 +501,7 @@ def builddashboard( request, build_id ):
499 if ( ndx < 0 ): 501 if ( ndx < 0 ):
500 ndx = 0; 502 ndx = 0;
501 f = i.file_name[ ndx + 1: ] 503 f = i.file_name[ ndx + 1: ]
502 imageFiles.append({ 'path': f, 'size' : i.file_size }) 504 imageFiles.append({ 'id': i.id, 'path': f, 'size' : i.file_size })
503 if ( t.is_image and 505 if ( t.is_image and
504 (( len( imageFiles ) <= 0 ) or ( len( t.license_manifest_path ) <= 0 ))): 506 (( len( imageFiles ) <= 0 ) or ( len( t.license_manifest_path ) <= 0 ))):
505 targetHasNoImages = True 507 targetHasNoImages = True
@@ -517,6 +519,8 @@ def builddashboard( request, build_id ):
517 if ( p.installed_name ): 519 if ( p.installed_name ):
518 packageCount = packageCount + 1 520 packageCount = packageCount + 1
519 521
522 logmessages = list(LogMessage.objects.filter( build = build_id ))
523
520 context = { 524 context = {
521 'build' : build, 525 'build' : build,
522 'hasImages' : hasImages, 526 'hasImages' : hasImages,
@@ -524,7 +528,7 @@ def builddashboard( request, build_id ):
524 'targets' : targets, 528 'targets' : targets,
525 'recipecount' : recipeCount, 529 'recipecount' : recipeCount,
526 'packagecount' : packageCount, 530 'packagecount' : packageCount,
527 'logmessages' : LogMessage.objects.filter( build = build_id ), 531 'logmessages' : logmessages,
528 } 532 }
529 return render( request, template, context ) 533 return render( request, template, context )
530 534
@@ -637,6 +641,9 @@ def target_common( request, build_id, target_id, variant ):
637 Package, queryset, filter_string, search_term, ordering_string, 'name' ) 641 Package, queryset, filter_string, search_term, ordering_string, 'name' )
638 packages = _build_page_range( Paginator(queryset, pagesize), request.GET.get( 'page', 1 )) 642 packages = _build_page_range( Paginator(queryset, pagesize), request.GET.get( 'page', 1 ))
639 643
644
645 build = Build.objects.get( pk = build_id )
646
640 # bring in package dependencies 647 # bring in package dependencies
641 for p in packages.object_list: 648 for p in packages.object_list:
642 p.runtime_dependencies = p.package_dependencies_source.filter( 649 p.runtime_dependencies = p.package_dependencies_source.filter(
@@ -697,8 +704,7 @@ eans multiple licenses exist that cover different parts of the source',
697 tc_dependencies[ "hidden" ] = 1 704 tc_dependencies[ "hidden" ] = 1
698 tc_rdependencies = { 705 tc_rdependencies = {
699 'name' : 'Reverse dependencies', 706 'name' : 'Reverse dependencies',
700 'qhelp' : 'Package run-time reverse dependencies (i.e. which other packages depend on t\ 707 'qhelp' : 'Package run-time reverse dependencies (i.e. which other packages depend on this package',
701his package',
702 'clclass' : 'brought_in_by', 708 'clclass' : 'brought_in_by',
703 } 709 }
704 if ( variant == 'target' ): 710 if ( variant == 'target' ):
@@ -741,18 +747,10 @@ his package',
741 'clclass' : 'layer_commit', 747 'clclass' : 'layer_commit',
742 'hidden' : 1, 748 'hidden' : 1,
743 } 749 }
744 tc_layerDir = { 750
745 'name':'Layer directory',
746 'qhelp':'Location in disk of the layer providing the recipe that builds the package',
747 'orderfield' : _get_toggle_order( request, "recipe__layer_version__layer__local_path" ),
748 'ordericon' : _get_toggle_order_icon( request, "recipe__layer_version__layer__local_path" )\
749,
750 'clclass' : 'layer_directory',
751 'hidden' : 1,
752 }
753 context = { 751 context = {
754 'objectname': variant, 752 'objectname': variant,
755 'build' : Build.objects.filter( pk = build_id )[ 0 ], 753 'build' : build,
756 'target' : Target.objects.filter( pk = target_id )[ 0 ], 754 'target' : Target.objects.filter( pk = target_id )[ 0 ],
757 'objects' : packages, 755 'objects' : packages,
758 'packages_sum' : packages_sum[ 'installed_size__sum' ], 756 'packages_sum' : packages_sum[ 'installed_size__sum' ],
@@ -771,10 +769,21 @@ his package',
771 tc_layer, 769 tc_layer,
772 tc_layerBranch, 770 tc_layerBranch,
773 tc_layerCommit, 771 tc_layerCommit,
774 tc_layerDir,
775 ] 772 ]
776 } 773 }
777 774
775 if not toastermain.settings.MANAGED or build.project is None:
776
777 tc_layerDir = {
778 'name':'Layer directory',
779 'qhelp':'Location in disk of the layer providing the recipe that builds the package',
780 'orderfield' : _get_toggle_order( request, "recipe__layer_version__layer__local_path" ),
781 'ordericon' : _get_toggle_order_icon( request, "recipe__layer_version__layer__local_path" ),
782 'clclass' : 'layer_directory',
783 'hidden' : 1,
784 }
785 context['tablecols'].append(tc_layerDir)
786
778 response = render(request, template, context) 787 response = render(request, template, context)
779 _save_parameters_cookies(response, pagesize, orderby, request) 788 _save_parameters_cookies(response, pagesize, orderby, request)
780 return response 789 return response
@@ -1136,12 +1145,13 @@ def tasks_common(request, build_id, variant, task_anchor):
1136 } 1145 }
1137 if 'diskio' == variant: tc_diskio['hidden']='0'; del tc_diskio['clclass']; tc_cache['hidden']='1'; 1146 if 'diskio' == variant: tc_diskio['hidden']='0'; del tc_diskio['clclass']; tc_cache['hidden']='1';
1138 1147
1148 build = Build.objects.get(pk=build_id)
1139 1149
1140 context = { 'objectname': variant, 1150 context = { 'objectname': variant,
1141 'object_search_display': object_search_display, 1151 'object_search_display': object_search_display,
1142 'filter_search_display': filter_search_display, 1152 'filter_search_display': filter_search_display,
1143 'title': title_variant, 1153 'title': title_variant,
1144 'build': Build.objects.get(pk=build_id), 1154 'build': build,
1145 'objects': tasks, 1155 'objects': tasks,
1146 'default_orderby' : orderby, 1156 'default_orderby' : orderby,
1147 'search_term': search_term, 1157 'search_term': search_term,
@@ -1157,9 +1167,12 @@ def tasks_common(request, build_id, variant, task_anchor):
1157 tc_time, 1167 tc_time,
1158 tc_cpu, 1168 tc_cpu,
1159 tc_diskio, 1169 tc_diskio,
1160 tc_log,
1161 ]} 1170 ]}
1162 1171
1172
1173 if not toastermain.settings.MANAGED or build.project is None:
1174 context['tablecols'].append(tc_log)
1175
1163 response = render(request, template, context) 1176 response = render(request, template, context)
1164 _save_parameters_cookies(response, pagesize, orderby, request) 1177 _save_parameters_cookies(response, pagesize, orderby, request)
1165 return response 1178 return response
@@ -1206,9 +1219,11 @@ def recipes(request, build_id):
1206 revlist.append(recipe_dep) 1219 revlist.append(recipe_dep)
1207 revs[recipe.id] = revlist 1220 revs[recipe.id] = revlist
1208 1221
1222 build = Build.objects.get(pk=build_id)
1223
1209 context = { 1224 context = {
1210 'objectname': 'recipes', 1225 'objectname': 'recipes',
1211 'build': Build.objects.get(pk=build_id), 1226 'build': build,
1212 'objects': recipes, 1227 'objects': recipes,
1213 'default_orderby' : 'name:+', 1228 'default_orderby' : 'name:+',
1214 'recipe_deps' : deps, 1229 'recipe_deps' : deps,
@@ -1279,6 +1294,11 @@ def recipes(request, build_id):
1279 'qhelp':'The Git commit of the layer providing the recipe', 1294 'qhelp':'The Git commit of the layer providing the recipe',
1280 'clclass': 'layer_version__layer__commit', 'hidden': 1, 1295 'clclass': 'layer_version__layer__commit', 'hidden': 1,
1281 }, 1296 },
1297 ]
1298 }
1299
1300 if not toastermain.settings.MANAGED or build.project is None:
1301 context['tablecols'].append(
1282 { 1302 {
1283 'name':'Layer directory', 1303 'name':'Layer directory',
1284 'qhelp':'Path to the layer prodiving the recipe', 1304 'qhelp':'Path to the layer prodiving the recipe',
@@ -1286,9 +1306,8 @@ def recipes(request, build_id):
1286 'ordericon':_get_toggle_order_icon(request, "layer_version__layer__local_path"), 1306 'ordericon':_get_toggle_order_icon(request, "layer_version__layer__local_path"),
1287 'orderkey' : 'layer_version__layer__local_path', 1307 'orderkey' : 'layer_version__layer__local_path',
1288 'clclass': 'layer_version__layer__local_path', 'hidden': 1, 1308 'clclass': 'layer_version__layer__local_path', 'hidden': 1,
1289 }, 1309 })
1290 ] 1310
1291 }
1292 1311
1293 response = render(request, template, context) 1312 response = render(request, template, context)
1294 _save_parameters_cookies(response, pagesize, orderby, request) 1313 _save_parameters_cookies(response, pagesize, orderby, request)
@@ -2685,41 +2704,53 @@ if toastermain.settings.MANAGED:
2685 return render(request, template, context) 2704 return render(request, template, context)
2686 2705
2687 2706
2707 def _file_name_for_artifact(b, artifact_type, artifact_id):
2708 file_name = None
2709 # Target_Image_File file_name
2710 if artifact_type == "imagefile":
2711 file_name = Target_Image_File.objects.get(target__build = b, pk = artifact_id).file_name
2688 2712
2689 def build_artifact(request, build_id, artifact_type, artifact_id): 2713 elif artifact_type == "cookerlog":
2690 try: 2714 file_name = b.cooker_log_path
2691 b = Build.objects.get(pk=build_id) 2715
2692 if b.buildrequest is None or b.buildrequest.environment is None: 2716 elif artifact_type == "buildartifact":
2693 raise Exception("Cannot download file") 2717 file_name = BuildArtifact.objects.get(build = b, pk = artifact_id).file_name
2694 2718
2695 file_name = None 2719 elif artifact_type == "licensemanifest":
2696 fsock = None 2720 file_name = Target.objects.get(build = b, pk = artifact_id).license_manifest_path
2697 content_type='application/force-download'
2698 # Target_Image_File file_name
2699 # Task logfile
2700 if artifact_type == "tasklogfile":
2701 file_name = Task.objects.get(build = b, pk = artifact_id).logfile
2702 2721
2703 # Task path_to_sstate_obj 2722 elif artifact_type == "tasklogfile":
2704 # Package_File path 2723 file_name = Task.objects.get(build = b, pk = artifact_id).logfile
2705 # Recipe file_path
2706 # VariableHistory file_name
2707 # LogMessage pathname
2708 if artifact_type == "logmessagefile":
2709 file_name = LogMessage.objects.get(build = b, pk = artifact_id).pathname
2710 2724
2711 if file_name is not None: 2725 elif artifact_type == "logmessagefile":
2712 content_type = b.buildrequest.environment.get_artifact_type(file_name) 2726 file_name = LogMessage.objects.get(build = b, pk = artifact_id).pathname
2713 fsock = b.buildrequest.environment.get_artifact(file_name) 2727 else:
2714 file_name = os.path.basename(file_name) 2728 raise Exception("FIXME: artifact type %s not implemented" % (artifact_type))
2715 2729
2716 response = HttpResponse(fsock, content_type = content_type) 2730 return file_name
2717 2731
2718 # returns a file from the environment 2732
2719 response['Content-Disposition'] = 'attachment; filename=' + file_name 2733 def build_artifact(request, build_id, artifact_type, artifact_id):
2720 return response 2734 b = Build.objects.get(pk=build_id)
2721 except: 2735 if b.buildrequest is None or b.buildrequest.environment is None:
2722 raise 2736 raise Exception("Artifact not available for download (missing build request or build environment)")
2737
2738 file_name = _file_name_for_artifact(b, artifact_type, artifact_id)
2739 fsock = None
2740 content_type='application/force-download'
2741
2742 if file_name is None:
2743 raise Exception("Could not handle artifact %s id %s" % (artifact_type, artifact_id))
2744 else:
2745 content_type = b.buildrequest.environment.get_artifact_type(file_name)
2746 fsock = b.buildrequest.environment.get_artifact(file_name)
2747 file_name = os.path.basename(file_name) # we assume that the build environment system has the same path conventions as host
2748
2749 response = HttpResponse(fsock, content_type = content_type)
2750
2751 # returns a file from the environment
2752 response['Content-Disposition'] = 'attachment; filename=' + file_name
2753 return response
2723 2754
2724 2755
2725 2756
@@ -2856,3 +2887,6 @@ else:
2856 2887
2857 def projects(request): 2888 def projects(request):
2858 raise Exception("page not available in interactive mode") 2889 raise Exception("page not available in interactive mode")
2890
2891 def xhr_importlayer(request):
2892 raise Exception("page not available in interactive mode")