Skip to content

Commit a96449f

Browse files
Akos Kittakittaakos
Akos Kitta
authored andcommitted
ATL-658: IDE can use any pinned version of CLI.
- Pinned the CLI to the `20201104` nightly. - Updated the TS/JS API generator to fall back to forks if configured. - Updated the CLI JSON schema. Signed-off-by: Akos Kitta <kittaakos@typefox.io>
1 parent c78e474 commit a96449f

File tree

7 files changed

+207
-55
lines changed

7 files changed

+207
-55
lines changed

arduino-ide-extension/README.md

+4
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,7 @@ The Config Service knows about your system, like for example the default sketch
5050
- [src/node/config-service-impl.ts](./src/node/config-service-impl.ts) implements the service backend:
5151
- getting the `arduino-cli` version and configuration
5252
- checking whether a file is in a data or sketch directory
53+
54+
### `"arduino"` configuration in the `package.json`:
55+
- `"cli"`:
56+
- `"version"` type `string` | `{ owner: string, repo: string, commitish?: string }`: if the type is a `string` and is a valid semver, it will get the corresponding [released](https://github.com/arduino/arduino-cli/releases) CLI. If the type is `string` and is a [date in `YYYYMMDD`](https://arduino.github.io/arduino-cli/latest/installation/#nightly-builds) format, it will get a nightly CLI. If the type is an object, a CLI, build from the sources in the `owner/repo` will be used. If `commitish` is not defined, the HEAD of the default branch will be used. In any other cases an error is thrown.

arduino-ide-extension/data/cli/schema/arduino-cli.schema.json

+11-3
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,17 @@
9292
},
9393
"additionalProperties": false
9494
},
95+
"sketch": {
96+
"type": "object",
97+
"description": "Sketch Configuration",
98+
"properties": {
99+
"always_export_binaries": {
100+
"type": "boolean",
101+
"description": "Controls whether the compiled binaries will be exported into the sketch's 'build' folder or not. 'false' if the binaries are not exported."
102+
}
103+
},
104+
"additionalProperties": false
105+
},
95106
"telemetry": {
96107
"type": "object",
97108
"description": "Telemetry Configuration",
@@ -110,8 +121,5 @@
110121
"additionalProperties": false
111122
}
112123
},
113-
"// TODOs": [
114-
"additionalProperties should be true. See the new telemetry entry"
115-
],
116124
"additionalProperties": false
117125
}

arduino-ide-extension/package.json

+7-2
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
"p-queue": "^5.0.0",
5858
"ps-tree": "^1.2.0",
5959
"react-select": "^3.0.4",
60-
"semver": "^6.3.0",
60+
"semver": "^7.3.2",
6161
"string-natural-compare": "^2.0.3",
6262
"temp": "^0.9.1",
6363
"tree-kill": "^1.2.1",
@@ -117,5 +117,10 @@
117117
{
118118
"electronMain": "lib/electron-main/arduino-electron-main-module"
119119
}
120-
]
120+
],
121+
"arduino": {
122+
"cli": {
123+
"version": "20201102"
124+
}
125+
}
121126
}
+126-47
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,141 @@
11
// @ts-check
2-
// The links to the downloads as of today (02.09.) are the followings:
3-
// In order to get the latest nightly build for your platform use the following links replacing <DATE> with the current date, using the format YYYYMMDD (i.e for 2019/Aug/06 use 20190806 )
4-
// Linux 64 bit: https://downloads.arduino.cc/arduino-cli/nightly/arduino-cli_nightly-<DATE>_Linux_64bit.tar.gz
5-
// Linux ARM 64 bit: https://downloads.arduino.cc/arduino-cli/nightly/arduino-cli_nightly-<DATE>_Linux_ARM64.tar.gz
6-
// Windows 64 bit: https://downloads.arduino.cc/arduino-cli/nightly/arduino-cli_nightly-<DATE>_Windows_64bit.zip
7-
// Mac OSX: https://downloads.arduino.cc/arduino-cli/nightly/arduino-cli_nightly-<DATE>_macOS_64bit.tar.gz
8-
// [...]
9-
// redirecting to latest generated builds by replacing latest with the latest available build date, using the format YYYYMMDD (i.e for 2019/Aug/06 latest is replaced with 20190806
102

11-
(() => {
12-
13-
const DEFAULT_VERSION = '0.13.0'; // require('moment')().format('YYYYMMDD');
3+
(async () => {
144

5+
const fs = require('fs');
156
const path = require('path');
7+
const temp = require('temp');
168
const shell = require('shelljs');
9+
const semver = require('semver');
10+
const moment = require('moment');
1711
const downloader = require('./downloader');
1812

19-
const yargs = require('yargs')
20-
.option('cli-version', {
21-
alias: 'cv',
22-
default: DEFAULT_VERSION,
23-
describe: `The version of the 'arduino-cli' to download, or 'nightly-latest'. Defaults to ${DEFAULT_VERSION}.`
24-
})
25-
.option('force-download', {
26-
alias: 'fd',
27-
default: false,
28-
describe: `If set, this script force downloads the 'arduino-cli' even if it already exists on the file system.`
29-
})
30-
.version(false).parse();
31-
32-
const version = yargs['cli-version'];
33-
const force = yargs['force-download'];
34-
const { platform, arch } = process;
13+
const version = (() => {
14+
const pkg = require(path.join(__dirname, '..', 'package.json'));
15+
if (!pkg) {
16+
return undefined;
17+
}
3518

36-
const build = path.join(__dirname, '..', 'build');
37-
const cli = path.join(build, `arduino-cli${platform === 'win32' ? '.exe' : ''}`);
38-
39-
const suffix = (() => {
40-
switch (platform) {
41-
case 'darwin': return 'macOS_64bit.tar.gz';
42-
case 'win32': return 'Windows_64bit.zip';
43-
case 'linux': {
44-
switch (arch) {
45-
case 'arm': return 'Linux_ARMv7.tar.gz';
46-
case 'arm64': return 'Linux_ARM64.tar.gz';
47-
case 'x64': return 'Linux_64bit.tar.gz';
48-
default: return undefined;
49-
}
50-
}
51-
default: return undefined;
19+
const { arduino } = pkg;
20+
if (!arduino) {
21+
return undefined;
5222
}
23+
24+
const { cli } = arduino;
25+
if (!cli) {
26+
return undefined;
27+
}
28+
29+
const { version } = cli;
30+
return version;
5331
})();
54-
if (!suffix) {
55-
shell.echo(`The CLI is not available for ${platform} ${arch}.`);
32+
33+
if (!version) {
34+
shell.echo(`Could not retrieve CLI version info from the 'package.json'.`);
5635
shell.exit(1);
5736
}
5837

59-
const url = `https://downloads.arduino.cc/arduino-cli${version.startsWith('nightly-') ? '/nightly' : ''}/arduino-cli_${version}_${suffix}`;
60-
downloader.downloadUnzipFile(url, cli, 'arduino-cli', force);
38+
const { platform, arch } = process;
39+
const buildFolder = path.join(__dirname, '..', 'build');
40+
const cliName = `arduino-cli${platform === 'win32' ? '.exe' : ''}`;
41+
const destinationPath = path.join(buildFolder, cliName);
42+
43+
if (typeof version === 'string') {
44+
const suffix = (() => {
45+
switch (platform) {
46+
case 'darwin': return 'macOS_64bit.tar.gz';
47+
case 'win32': return 'Windows_64bit.zip';
48+
case 'linux': {
49+
switch (arch) {
50+
case 'arm': return 'Linux_ARMv7.tar.gz';
51+
case 'arm64': return 'Linux_ARM64.tar.gz';
52+
case 'x64': return 'Linux_64bit.tar.gz';
53+
default: return undefined;
54+
}
55+
}
56+
default: return undefined;
57+
}
58+
})();
59+
if (!suffix) {
60+
shell.echo(`The CLI is not available for ${platform} ${arch}.`);
61+
shell.exit(1);
62+
}
63+
if (semver.valid(version)) {
64+
const url = `https://downloads.arduino.cc/arduino-cli/arduino-cli_${version}_${suffix}`;
65+
shell.echo(`📦 Identified released version of the CLI. Downloading version ${version} from '${url}'`);
66+
await downloader.downloadUnzipFile(url, destinationPath, 'arduino-cli');
67+
} else if (moment(version, 'YYYYMMDD', true).isValid()) {
68+
const url = `https://downloads.arduino.cc/arduino-cli/nightly/arduino-cli_nightly-${version}_${suffix}`;
69+
shell.echo(`🌙 Identified nightly version of the CLI. Downloading version ${version} from '${url}'`);
70+
await downloader.downloadUnzipFile(url, destinationPath, 'arduino-cli');
71+
} else {
72+
shell.echo(`🔥 Could not interpret 'version': ${version}`);
73+
shell.exit(1);
74+
}
75+
} else {
76+
77+
// We assume an object with `owner`, `repo`, commitish?` properties.
78+
const { owner, repo, commitish } = version;
79+
if (!owner) {
80+
shell.echo(`Could not retrieve 'owner' from ${JSON.stringify(version)}`);
81+
shell.exit(1);
82+
}
83+
if (!repo) {
84+
shell.echo(`Could not retrieve 'repo' from ${JSON.stringify(version)}`);
85+
shell.exit(1);
86+
}
87+
const url = `https://github.com/${owner}/${repo}.git`;
88+
shell.echo(`Building CLI from ${url}. Commitish: ${commitish ? commitish : 'HEAD'}`);
89+
90+
if (fs.existsSync(destinationPath)) {
91+
shell.echo(`Skipping the CLI build because it already exists: ${destinationPath}`);
92+
return;
93+
}
94+
95+
if (shell.mkdir('-p', buildFolder).code !== 0) {
96+
shell.echo('Could not create build folder.');
97+
shell.exit(1);
98+
}
99+
100+
const tempRepoPath = temp.mkdirSync();
101+
shell.echo(`>>> Cloning CLI source to ${tempRepoPath}...`);
102+
if (shell.exec(`git clone ${url} ${tempRepoPath}`).code !== 0) {
103+
shell.exit(1);
104+
}
105+
shell.echo('<<< Cloned CLI repo.')
106+
107+
if (commitish) {
108+
shell.echo(`>>> Checking out ${commitish}...`);
109+
if (shell.exec(`git -C ${tempRepoPath} checkout ${commitish}`).code !== 0) {
110+
shell.exit(1);
111+
}
112+
shell.echo(`<<< Checked out ${commitish}.`);
113+
}
114+
115+
shell.echo(`>>> Building the CLI...`);
116+
if (shell.exec('go build', { cwd: tempRepoPath }).code !== 0) {
117+
shell.exit(1);
118+
}
119+
shell.echo('<<< CLI build done.')
120+
121+
if (!fs.existsSync(path.join(tempRepoPath, cliName))) {
122+
shell.echo(`Could not find the CLI at ${path.join(tempRepoPath, cliName)}.`);
123+
shell.exit(1);
124+
}
125+
126+
const builtCliPath = path.join(tempRepoPath, cliName);
127+
shell.echo(`>>> Copying CLI from ${builtCliPath} to ${destinationPath}...`);
128+
if (shell.cp(builtCliPath, destinationPath).code !== 0) {
129+
shell.exit(1);
130+
}
131+
shell.echo(`<<< Copied the CLI.`);
132+
133+
shell.echo('<<< Verifying CLI...');
134+
if (!fs.existsSync(destinationPath)) {
135+
shell.exit(1);
136+
}
137+
shell.echo('>>> Verified CLI.');
138+
139+
}
61140

62141
})();

arduino-ide-extension/scripts/downloader.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ process.on('uncaughtException', error => {
2121
* @param url {string} Download URL
2222
* @param targetFile {string} Path to the file to copy from the decompressed archive
2323
* @param filePrefix {string} Prefix of the file name found in the archive
24-
* @param force {boolean} Whether to download even if the target file exists
24+
* @param force {boolean} Whether to download even if the target file exists. `false` by default.
2525
*/
26-
exports.downloadUnzipFile = async (url, targetFile, filePrefix, force) => {
26+
exports.downloadUnzipFile = async (url, targetFile, filePrefix, force = false) => {
2727
if (fs.existsSync(targetFile) && !force) {
2828
shell.echo(`Skipping download because file already exists: ${targetFile}`);
2929
return;

arduino-ide-extension/scripts/generate-protocol.js

+52-1
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,52 @@
1616
shell.exit(1);
1717
}
1818

19-
if (shell.exec(`git clone --depth 1 https://github.com/arduino/arduino-cli.git ${repository}`).code !== 0) {
19+
const { owner, repo, commitish } = (() => {
20+
const pkg = require(path.join(__dirname, '..', 'package.json'));
21+
if (!pkg) {
22+
shell.echo(`Could not parse the 'package.json'.`);
23+
shell.exit(1);
24+
}
25+
26+
const { arduino } = pkg;
27+
if (!arduino) {
28+
return { owner: 'arduino', repo: 'arduino-cli' };
29+
}
30+
31+
const { cli } = arduino;
32+
if (!cli) {
33+
return { owner: 'arduino', repo: 'arduino-cli' };
34+
}
35+
36+
const { version } = cli;
37+
if (!version) {
38+
return { owner: 'arduino', repo: 'arduino-cli' };
39+
}
40+
41+
if (typeof version === 'string') {
42+
return { owner: 'arduino', repo: 'arduino-cli' };
43+
}
44+
45+
// We assume an object with `owner`, `repo`, commitish?` properties.
46+
const { owner, repo, commitish } = version;
47+
if (!owner) {
48+
shell.echo(`Could not retrieve 'owner' from ${JSON.stringify(version)}`);
49+
shell.exit(1);
50+
}
51+
if (!repo) {
52+
shell.echo(`Could not retrieve 'repo' from ${JSON.stringify(version)}`);
53+
shell.exit(1);
54+
}
55+
56+
return { owner, repo, commitish };
57+
})();
58+
59+
const url = `https://github.com/${owner}/${repo}.git`;
60+
shell.echo(`>>> Cloning repository from '${url}'...`);
61+
if (shell.exec(`git clone ${url} ${repository}`).code !== 0) {
2062
shell.exit(1);
2163
}
64+
shell.echo(`<<< Repository cloned.`);
2265

2366
const { platform } = process;
2467
const build = path.join(__dirname, '..', 'build');
@@ -30,9 +73,17 @@
3073
}
3174
const version = rawVersion.substring(rawVersion.lastIndexOf('Commit:') + 'Commit:'.length).trim();
3275
if (version) {
76+
shell.echo(`>>> Checking out version: ${version}...`);
3377
if (shell.exec(`git -C ${repository} checkout ${version} -b ${version}`).code !== 0) {
3478
shell.exit(1);
3579
}
80+
shell.echo(`<<< Checked out version: ${commitish}.`);
81+
} else if (commitish) {
82+
shell.echo(`>>> Checking out commitish: ${commitish}...`);
83+
if (shell.exec(`git -C ${repository} checkout ${commitish}`).code !== 0) {
84+
shell.exit(1);
85+
}
86+
shell.echo(`<<< Checked out commitish: ${commitish}.`);
3687
}
3788

3889
shell.echo('>>> Generating TS/JS API from:');

arduino-ide-extension/src/node/config-file-validator.ts

+5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ export class ConfigFileValidator {
1515
protected async doValidate(object: object): Promise<boolean> {
1616
const valid = this.function(object);
1717
if (!valid) {
18+
if (Array.isArray(this.function.errors)) {
19+
for (const error of this.function.errors) {
20+
console.log(JSON.stringify(error));
21+
}
22+
}
1823
return false;
1924
}
2025
if (!DefaultCliConfig.is(object)) {

0 commit comments

Comments
 (0)