summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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")