| // Copyright (C) 2022 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| // Helper function to create DOM elements faster: takes a Mithril-style |
| // "selector" of the form "tag.class1.class2" and a list of child objects that |
| // can be either strings or DOM elements. |
| function m(selector, ...children) { |
| const parts = selector.split('.'); |
| if (parts.length === 0) { |
| throw new Error( |
| 'Selector passed to element should be of a form tag.class1.class2'); |
| } |
| |
| const result = document.createElement(parts[0]); |
| for (let i = 1; i < parts.length; i++) { |
| result.classList.add(parts[i]); |
| } |
| for (const child of children) { |
| if (typeof child === 'string') { |
| const childNode = document.createTextNode(child); |
| result.appendChild(childNode); |
| } else { |
| result.appendChild(child); |
| } |
| } |
| return result; |
| } |
| |
| function getCiRun() { |
| const url = new URL(window.location.href); |
| const parts = url.pathname.split('/'); |
| |
| // Example report URL: |
| // https://storage.googleapis.com/perfetto-ci-artifacts/20220711123401--cls-2149676-1--ui-clang-x86_64-release/ui-test-artifacts/index.html |
| // Parts would contain ['', 'perfetto-ci-artifacts', |
| // '20220711123401--cls-2149676-1--ui-clang-x86_64-release', ...] in this |
| // case, which means that we need to check length of the array and get third |
| // element out of it. |
| if (parts.length >= 3) { |
| return parts[2]; |
| } |
| return null; |
| } |
| |
| function imageLinkElement(path) { |
| const img = m('img'); |
| img.src = path; |
| const link = m('a'); |
| link.appendChild(img); |
| link.href = path; |
| link.target = '_blank'; |
| return link; |
| } |
| |
| function processLines(lines) { |
| const container = document.querySelector('.container'); |
| container.innerHTML = ''; |
| const children = []; |
| |
| // report.txt is a text file with a pair of file names on each line, separated |
| // by semicolon. E.g. "screenshot.png;screenshot-diff.png" |
| for (const line of lines) { |
| // Skip empty lines (happens when the file is completely empty). |
| if (line.length === 0) { |
| continue; |
| } |
| |
| const parts = line.split(';'); |
| if (parts.length !== 2) { |
| console.warn( |
| `Malformed line (expected two files separated via semicolon) ${ |
| line}!`); |
| continue; |
| } |
| |
| const [output, diff] = parts; |
| children.push(m( |
| 'div.row', |
| m('div.cell', output, m('div.image-wrapper', imageLinkElement(output))), |
| m('div.cell', diff, m('div.image-wrapper', imageLinkElement(diff))))); |
| } |
| |
| if (children.length === 0) { |
| container.appendChild(m('div', 'All good!')); |
| return; |
| } |
| |
| const run = getCiRun(); |
| |
| if (run !== null) { |
| const cmd = `tools/download_changed_screenshots.py ${run}`; |
| const button = m('button', 'Copy'); |
| button.addEventListener('click', async () => { |
| await navigator.clipboard.writeText(cmd); |
| button.innerText = 'Copied!'; |
| }); |
| |
| container.appendChild(m( |
| 'div.message', |
| 'Use following command from Perfetto checkout directory to apply the ' + |
| 'changes: ', |
| m('span.cmd', cmd), |
| button)); |
| } |
| |
| for (const child of children) { |
| container.appendChild(child); |
| } |
| } |
| |
| async function loadDiffs() { |
| try { |
| const report = await fetch('report.txt'); |
| const response = await report.text(); |
| processLines(response.split('\n')); |
| } catch (e) { |
| // report.txt is not available when all tests have succeeded, treat fetching |
| // error as absence of failures |
| processLines([]); |
| } |
| } |
| |
| document.addEventListener('DOMContentLoaded', () => { |
| loadDiffs(); |
| }); |