Skip to content

Commit 22f4866

Browse files
committed
Support flashing zip files on Tachyon
1 parent 14deaf3 commit 22f4866

File tree

3 files changed

+106
-68
lines changed

3 files changed

+106
-68
lines changed

src/cmd/flash.js

Lines changed: 91 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const CloudCommand = require('./cloud');
1212
const BundleCommand = require('./bundle');
1313
const temp = require('temp').track();
1414
const { knownAppNames, knownAppsForPlatform } = require('../lib/known-apps');
15-
const { sourcePatterns, binaryPatterns, binaryExtensions, linuxExecPatterns } = require('../lib/file-types');
15+
const { sourcePatterns, binaryPatterns, binaryExtensions } = require('../lib/file-types');
1616
const deviceOsUtils = require('../lib/device-os-version-util');
1717
const os = require('os');
1818
const semver = require('semver');
@@ -26,8 +26,11 @@ const {
2626
} = require('../lib/flash-helper');
2727
const createApiCache = require('../lib/api-cache');
2828
const { validateDFUSupport } = require('./device-util');
29+
const unzip = require('unzipper');
2930
const qdl = require('../lib/qdl');
3031

32+
const TACHYON_MANIFEST_FILE = 'release.json';
33+
3134
module.exports = class FlashCommand extends CLICommandBase {
3235
constructor(...args) {
3336
super(...args);
@@ -70,63 +73,105 @@ module.exports = class FlashCommand extends CLICommandBase {
7073
async flashTachyon({ verbose, files }) {
7174
this.ui.write(`${os.EOL}Ensure only one device is connected to the computer${os.EOL}`);
7275

73-
let unpackToolFolder;
74-
if (files.length === 0) {
75-
// If no files are passed, assume the current directory
76-
unpackToolFolder = process.cwd();
77-
files = await fs.readdir(unpackToolFolder);
78-
} else if (files.length === 1) {
79-
// If only one file is passed, check if it's a directory
80-
const stats = await fs.stat(files[0]);
76+
let zipFile;
77+
let includeDir;
78+
let firehoseElf;
79+
let programXmlFilesWithPath;
80+
let patchXmlFilesWithPath;
81+
82+
const readManifest = async (manifestPath) => {
83+
const manifestFile = await fs.readFile(manifestPath, 'utf8');
84+
const manifestData = JSON.parse(manifestFile);
85+
86+
const base = manifestData.targets[0].qcm6490.edl.base;
87+
const firehose = manifestData.targets[0].qcm6490.edl.firehose;
88+
const programXmlFiles = manifestData.targets[0].qcm6490.edl.program_xml;
89+
const patchXmlFiles = manifestData.targets[0].qcm6490.edl.patch_xml;
90+
91+
const baseDir = path.join(path.dirname(manifestPath), base);
92+
const programXmlFilesWithPath = programXmlFiles.map(p => path.join(baseDir, p));
93+
const patchXmlFilesWithPath = patchXmlFiles.map(p => path.join(baseDir, p));
94+
95+
return { baseDir, firehose, programXmlFilesWithPath, patchXmlFilesWithPath };
96+
};
97+
98+
const extractZipManifest = async (zipPath) => {
99+
const dir = await unzip.Open.file(zipPath);
100+
const zipName = path.basename(zipPath, '.zip');
101+
const manifestFile = dir.files.find(file => file.path === path.join(zipName, TACHYON_MANIFEST_FILE));
102+
if (!manifestFile) {
103+
throw new Error(`Unable to find ${TACHYON_MANIFEST_FILE}${os.EOL}`);
104+
}
105+
106+
const manifest = await manifestFile.buffer();
107+
const manifestData = JSON.parse(manifest.toString());
108+
109+
const baseDir = manifestData.targets[0].qcm6490.edl.base;
110+
const firehose = manifestData.targets[0].qcm6490.edl.firehose;
111+
const programXmlFiles = manifestData.targets[0].qcm6490.edl.program_xml;
112+
const patchXmlFiles = manifestData.targets[0].qcm6490.edl.patch_xml;
113+
114+
const programXmlFilesWithPath = programXmlFiles.map(p => path.join(baseDir, p));
115+
const patchXmlFilesWithPath = patchXmlFiles.map(p => path.join(baseDir, p));
116+
return { baseDir, firehose, programXmlFilesWithPath, patchXmlFilesWithPath };
117+
};
118+
119+
const sortByNumber = (a, b) => {
120+
const extractNumber = str => parseInt(str.match(/(\d+).xml/)[1], 10);
121+
return extractNumber(a) - extractNumber(b);
122+
};
123+
124+
if (files.length <= 1) {
125+
// If no files are passed, use the current directory
126+
const input = files.length === 1 ? files[0] : process.cwd();
127+
const stats = await fs.stat(input);
128+
81129
if (stats.isDirectory()) {
82-
unpackToolFolder = files[0];
83-
files = await fs.readdir(files[0]);
130+
const manifestPath = path.join(input, TACHYON_MANIFEST_FILE);
131+
if (!fs.existsSync(manifestPath)) {
132+
throw new Error(`Unable to find ${TACHYON_MANIFEST_FILE}${os.EOL}`);
133+
}
134+
({ baseDir: includeDir, firehose: firehoseElf, programXmlFilesWithPath, patchXmlFilesWithPath } = await readManifest(manifestPath));
135+
} else if (utilities.getFilenameExt(input) === '.zip') {
136+
zipFile = path.basename(input);
137+
({ baseDir: includeDir, firehose: firehoseElf, programXmlFilesWithPath, patchXmlFilesWithPath } = await extractZipManifest(input));
138+
} else {
139+
throw new Error(`The provided file is not a directory or a zip file${os.EOL}`);
84140
}
85141
} else {
86-
// If multiple files are passed, check the directory from the first file
87-
unpackToolFolder = path.dirname(files[0]);
142+
includeDir = path.dirname(files[0]);
143+
firehoseElf = files.filter(f => f.includes('firehose') && f.endsWith('.elf'));
144+
programXmlFilesWithPath = files.filter(f => f.startsWith('rawprogram') && f.endsWith('.xml'));
145+
patchXmlFilesWithPath = files.filter(f => f.startsWith('patch') && f.endsWith('.xml'));
88146
}
89147

90-
let linxuFiles = await this._findLinuxExecutableFiles(files, { directory: unpackToolFolder });
91-
linxuFiles = linxuFiles.map(f => path.basename(f));
92-
93-
const elfFiles = linxuFiles.filter(f => f.includes('firehose') && f.endsWith('.elf'));
94-
const rawProgramFiles = linxuFiles.filter(f => f.startsWith('rawprogram') && f.endsWith('.xml'));
95-
const patchFiles = linxuFiles.filter(f => f.startsWith('patch') && f.endsWith('.xml'));
96-
97-
if (!elfFiles.length || !rawProgramFiles.length) {
148+
if (!firehoseElf.length || !programXmlFilesWithPath.length) {
98149
throw new Error('The directory should contain at least one .elf file and one rawprogram file');
99150
}
100151

101-
const sortByNumber = (a, b) => {
102-
const extractNumber = str => parseInt(str.match(/(\d+).xml/)[1]);
103-
return extractNumber(a) - extractNumber(b);
104-
};
105-
106-
rawProgramFiles.sort(sortByNumber);
107-
patchFiles.sort(sortByNumber);
152+
programXmlFilesWithPath.sort(sortByNumber);
153+
patchXmlFilesWithPath.sort(sortByNumber);
108154

109155
let filesToProgram = [];
110156
// interleave the rawprogram files and patch files
111-
for (let i = 0; i < rawProgramFiles.length; i++) {
112-
filesToProgram.push(rawProgramFiles[i]);
113-
filesToProgram.push(patchFiles[i]);
157+
for (let i = 0; i < programXmlFilesWithPath.length; i++) {
158+
filesToProgram.push(programXmlFilesWithPath[i]);
159+
filesToProgram.push(patchXmlFilesWithPath[i]);
114160
}
161+
filesToProgram.unshift(firehoseElf);
115162

116-
filesToProgram.unshift(elfFiles[0]);
117-
118-
this.ui.write(`Found the following files in the directory:${os.EOL}`);
163+
this.ui.write(`Found the following files:${os.EOL}`);
119164
this.ui.write(' Loader file:');
120-
this.ui.write(` - ${elfFiles[0]}${os.EOL}`);
165+
this.ui.write(` - ${firehoseElf}${os.EOL}`);
121166

122167
this.ui.write(' Program files:');
123-
for (const file of rawProgramFiles) {
168+
for (const file of programXmlFilesWithPath) {
124169
this.ui.write(` - ${file}`);
125170
}
126171
this.ui.write(os.EOL);
127172

128173
this.ui.write(' Patch files:');
129-
for (const file of patchFiles) {
174+
for (const file of patchXmlFilesWithPath) {
130175
this.ui.write(` - ${file}`);
131176
}
132177
this.ui.write(os.EOL);
@@ -136,7 +181,8 @@ module.exports = class FlashCommand extends CLICommandBase {
136181
try {
137182
const res = await qdl.run({
138183
files: filesToProgram,
139-
updateFolder: unpackToolFolder,
184+
updateFolder: includeDir,
185+
zip: zipFile,
140186
verbose,
141187
ui: this.ui
142188
});
@@ -387,37 +433,24 @@ module.exports = class FlashCommand extends CLICommandBase {
387433
}
388434

389435
async _findBinaries(parsedFiles) {
390-
return this._findFiles(parsedFiles, binaryPatterns);
391-
}
392-
393-
async _findLinuxExecutableFiles(parsedFiles, { directory }) {
394-
395-
if (directory) {
396-
const files = parsedFiles.map(f => path.join(directory, f));
397-
return this._findFiles(files, linuxExecPatterns);
398-
}
399-
return this._findFiles(parsedFiles, linuxExecPatterns);
400-
}
401-
402-
async _findFiles(files, patterns) {
403-
const resFiles = new Set();
404-
for (const filePath of files) {
436+
const binaries = new Set();
437+
for (const filePath of parsedFiles) {
405438
try {
406439
const stats = await fs.stat(filePath);
407440
if (stats.isDirectory()) {
408-
const found = utilities.globList(filePath, patterns);
409-
for (const file of found) {
410-
resFiles.add(file);
441+
const found = utilities.globList(filePath, binaryPatterns);
442+
for (const binary of found) {
443+
binaries.add(binary);
411444
}
412445
} else {
413-
resFiles.add(filePath);
446+
binaries.add(filePath);
414447
}
415448
} catch (error) {
416449
throw new Error(`I couldn't find that: ${filePath}`);
417450
}
418451

419452
}
420-
return Array.from(resFiles);
453+
return Array.from(binaries);
421454
}
422455

423456
async _processBundle({ filesToFlash }) {

src/lib/file-types.js

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,10 @@ const binaryExtensions = [
1515
'.zip'
1616
];
1717

18-
const linuxExecExtensions = [
19-
'.elf',
20-
'.xml'
21-
];
22-
2318
const binaryPatterns = binaryExtensions.map(ext => `*${ext}`);
24-
const linuxExecPatterns = linuxExecExtensions.map(ext => `*${ext}`);
2519

2620
module.exports = {
2721
sourcePatterns,
2822
binaryExtensions,
29-
binaryPatterns,
30-
linuxExecPatterns
23+
binaryPatterns
3124
};

src/lib/qdl.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const utilities = require('../lib/utilities');
33
const path = require('path');
44
const fs = require('fs-extra');
55
const os = require('os');
6+
const { update } = require('lodash');
67

78
const TACHYON_STORAGE_TYPE = 'ufs';
89

@@ -17,12 +18,23 @@ async function getExecutable() {
1718

1819
/**
1920
*/
20-
async function run({ files, updateFolder, verbose, ui }) {
21+
async function run({ files, updateFolder, zip, verbose, ui }) {
2122
const qdl = await getExecutable();
2223

2324
ui.write(`Command: ${qdl} --storage ${TACHYON_STORAGE_TYPE} ${files.join(' ')}${os.EOL}`);
2425

25-
const res = await execa(qdl, ['--storage', 'ufs', ...files], {
26+
const qdlArgs = [
27+
'--storage',
28+
TACHYON_STORAGE_TYPE,
29+
...(zip ? ['--zip', zip] : []),
30+
'--include',
31+
updateFolder,
32+
...files
33+
];
34+
35+
console.log('qdArgs', qdlArgs);
36+
37+
const res = await execa(qdl, qdlArgs, {
2638
cwd: updateFolder,
2739
stdio: verbose ? 'inherit' : 'pipe'
2840
});

0 commit comments

Comments
 (0)