mirror of
https://github.com/balena-io/balena-cli.git
synced 2025-06-24 18:45:07 +00:00
Compare commits
7 Commits
allow-cust
...
remove-etc
Author | SHA1 | Date | |
---|---|---|---|
61c7ee6239 | |||
5371fea588 | |||
bacb55a1ea | |||
ecfd4a260e | |||
1525822239 | |||
1614d9b2c8 | |||
2e061845ae |
36
.github/actions/publish/action.yml
vendored
36
.github/actions/publish/action.yml
vendored
@ -69,18 +69,11 @@ runs:
|
||||
if: runner.os == 'Windows'
|
||||
shell: powershell
|
||||
run: |
|
||||
Set-Content -Path ${{ runner.temp }}/certificate.base64 -Value $env:WINDOWS_CERTIFICATE
|
||||
certutil -decode ${{ runner.temp }}/certificate.base64 ${{ runner.temp }}/certificate.pfx
|
||||
Set-Content -Path ${{ runner.temp }}/certificate.base64 -Value $env:SM_CLIENT_CERT_FILE_B64
|
||||
certutil -decode ${{ runner.temp }}/certificate.base64 ${{ runner.temp }}/Certificate_pkcs12.p12
|
||||
Remove-Item -path ${{ runner.temp }} -include certificate.base64
|
||||
|
||||
Import-PfxCertificate `
|
||||
-FilePath ${{ runner.temp }}/certificate.pfx `
|
||||
-CertStoreLocation Cert:\CurrentUser\My `
|
||||
-Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText)
|
||||
|
||||
env:
|
||||
WINDOWS_CERTIFICATE: ${{ fromJSON(inputs.secrets).WINDOWS_SIGNING }}
|
||||
WINDOWS_CERTIFICATE_PASSWORD: ${{ fromJSON(inputs.secrets).WINDOWS_SIGNING_PASSWORD }}
|
||||
SM_CLIENT_CERT_FILE_B64: ${{ fromJSON(inputs.secrets).SM_CLIENT_CERT_FILE_B64 }}
|
||||
|
||||
# https://github.com/product-os/scripts/tree/master/shared
|
||||
# https://github.com/product-os/balena-concourse/blob/master/pipelines/github-events/template.yml
|
||||
@ -100,12 +93,21 @@ runs:
|
||||
CSC_LINK=${{ fromJSON(inputs.secrets).APPLE_SIGNING }}
|
||||
|
||||
elif [[ $runner_os =~ windows|win ]]; then
|
||||
CSC_KEY_PASSWORD=${{ fromJSON(inputs.secrets).WINDOWS_SIGNING_PASSWORD }}
|
||||
CSC_LINK='${{ runner.temp }}\certificate.pfx'
|
||||
SM_HOST=${{ fromJSON(inputs.secrets).SM_HOST }}
|
||||
SM_API_KEY=${{ fromJSON(inputs.secrets).SM_API_KEY }}
|
||||
SM_CLIENT_CERT_FILE='${{ runner.temp }}\Certificate_pkcs12.p12'
|
||||
SM_CLIENT_CERT_PASSWORD=${{ fromJSON(inputs.secrets).SM_CLIENT_CERT_PASSWORD }}
|
||||
SM_CODE_SIGNING_CERT_SHA1_HASH=${{ fromJSON(inputs.secrets).SM_CODE_SIGNING_CERT_SHA1_HASH }}
|
||||
|
||||
# patches/all/oclif.patch
|
||||
MSYSSHELLPATH="$(which bash)"
|
||||
MSYSTEM=MSYS
|
||||
curl --silent --retry 3 --fail https://one.digicert.com/signingmanager/api-ui/v1/releases/smtools-windows-x64.msi/download \
|
||||
-H "x-api-key:$SM_API_KEY" \
|
||||
-o smtools-windows-x64.msi
|
||||
msiexec -i smtools-windows-x64.msi -qn
|
||||
PATH="/c/Program Files/DigiCert/DigiCert One Signing Manager Tools:${PATH}"
|
||||
smksp_registrar.exe list
|
||||
smctl.exe keypair ls
|
||||
/c/Windows/System32/certutil.exe -csp "DigiCert Signing Manager KSP" -key -user
|
||||
smksp_cert_sync.exe
|
||||
|
||||
# (signtool.exe) https://github.com/actions/runner-images/blob/main/images/win/Windows2019-Readme.md#installed-windows-sdks
|
||||
PATH="/c/Program Files (x86)/Windows Kits/10/bin/${runner_arch}:${PATH}"
|
||||
@ -119,8 +121,8 @@ runs:
|
||||
# https://github.blog/2020-08-03-github-actions-improvements-for-fork-and-pull-request-workflows/#improvements-for-public-repository-forks
|
||||
# https://docs.github.com/en/actions/managing-workflow-runs/approving-workflow-runs-from-public-forks#about-workflow-runs-from-public-forks
|
||||
CSC_FOR_PULL_REQUEST: true
|
||||
# https://sectigo.com/resource-library/time-stamping-server
|
||||
TIMESTAMP_SERVER: http://timestamp.sectigo.com
|
||||
# https://docs.digicert.com/es/software-trust-manager/ci-cd-integrations/plugins/github-custom-action-for-keypair-signing.html
|
||||
TIMESTAMP_SERVER: http://timestamp.digicert.com
|
||||
# Apple notarization (automation/build-bin.ts)
|
||||
XCODE_APP_LOADER_EMAIL: ${{ inputs.XCODE_APP_LOADER_EMAIL }}
|
||||
XCODE_APP_LOADER_PASSWORD: ${{ fromJSON(inputs.secrets).XCODE_APP_LOADER_PASSWORD }}
|
||||
|
@ -1,3 +1,27 @@
|
||||
- commits:
|
||||
- subject: Remove no longer needed windows oclif patches
|
||||
hash: ecfd4a260e4734c768480b98d05cee08f366a672
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: Otavio Jacobi
|
||||
nested: []
|
||||
version: 18.0.2
|
||||
title: ""
|
||||
date: 2024-03-07T19:40:22.571Z
|
||||
- commits:
|
||||
- subject: Fix windows signing
|
||||
hash: 2e061845ae01fd6d3aa10c97bf8a68a8dba5dfd9
|
||||
body: ""
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
author: Otavio Jacobi
|
||||
nested: []
|
||||
version: 18.0.1
|
||||
title: ""
|
||||
date: 2024-03-07T16:30:09.344Z
|
||||
- commits:
|
||||
- subject: Update to Node 20
|
||||
hash: bf5e61a61c542f0c0a57ae49bb9a9998588d6851
|
||||
@ -1049,9 +1073,11 @@
|
||||
Bumps [lint-staged](https://github.com/okonet/lint-staged) from
|
||||
13.3.0 to 14.0.0.
|
||||
|
||||
- [Release notes](https://github.com/okonet/lint-staged/releases)
|
||||
- [Release
|
||||
notes](https://github.com/okonet/lint-staged/releases)
|
||||
|
||||
- [Commits](https://github.com/okonet/lint-staged/compare/v13.3.0...v14.0.0)
|
||||
-
|
||||
[Commits](https://github.com/okonet/lint-staged/compare/v13.3.0...v14.0.0)
|
||||
|
||||
|
||||
---
|
||||
@ -1391,9 +1417,11 @@
|
||||
[lint-staged](https://github.com/okonet/lint-staged)
|
||||
from 13.3.0 to 14.0.0.
|
||||
|
||||
- [Release notes](https://github.com/okonet/lint-staged/releases)
|
||||
- [Release
|
||||
notes](https://github.com/okonet/lint-staged/releases)
|
||||
|
||||
- [Commits](https://github.com/okonet/lint-staged/compare/v13.3.0...v14.0.0)
|
||||
-
|
||||
[Commits](https://github.com/okonet/lint-staged/compare/v13.3.0...v14.0.0)
|
||||
|
||||
|
||||
---
|
||||
@ -1768,9 +1796,11 @@
|
||||
[lint-staged](https://github.com/okonet/lint-staged)
|
||||
from 13.3.0 to 14.0.0.
|
||||
|
||||
- [Release notes](https://github.com/okonet/lint-staged/releases)
|
||||
- [Release
|
||||
notes](https://github.com/okonet/lint-staged/releases)
|
||||
|
||||
- [Commits](https://github.com/okonet/lint-staged/compare/v13.3.0...v14.0.0)
|
||||
-
|
||||
[Commits](https://github.com/okonet/lint-staged/compare/v13.3.0...v14.0.0)
|
||||
|
||||
|
||||
---
|
||||
@ -2969,7 +2999,8 @@
|
||||
Be more lenient with decoding compressed
|
||||
responses, since (very rarely)
|
||||
|
||||
servers send slightly invalid gzip responses that are still accepted
|
||||
servers send slightly invalid gzip responses
|
||||
that are still accepted
|
||||
|
||||
by common browsers.
|
||||
|
||||
@ -2989,7 +3020,8 @@
|
||||
body: >
|
||||
The only breaking change is dropping support
|
||||
|
||||
for node v8 but we have already done that in v11.
|
||||
for node v8 but we have already done that in
|
||||
v11.
|
||||
footer:
|
||||
Change-type: minor
|
||||
change-type: minor
|
||||
@ -3018,7 +3050,8 @@
|
||||
body: >
|
||||
Otherwise request from the browser could end up
|
||||
|
||||
on the domain of the current url. For the dashboard
|
||||
on the domain of the current url. For the
|
||||
dashboard
|
||||
|
||||
this would mean the UI nginx would respond with
|
||||
|
||||
@ -4296,7 +4329,8 @@
|
||||
Be more lenient with decoding compressed
|
||||
responses, since (very rarely)
|
||||
|
||||
servers send slightly invalid gzip responses that are still accepted
|
||||
servers send slightly invalid gzip responses
|
||||
that are still accepted
|
||||
|
||||
by common browsers.
|
||||
|
||||
@ -4316,7 +4350,8 @@
|
||||
body: >
|
||||
The only breaking change is dropping support
|
||||
|
||||
for node v8 but we have already done that in v11.
|
||||
for node v8 but we have already done that in
|
||||
v11.
|
||||
footer:
|
||||
Change-type: minor
|
||||
change-type: minor
|
||||
@ -4345,7 +4380,8 @@
|
||||
body: >
|
||||
Otherwise request from the browser could end up
|
||||
|
||||
on the domain of the current url. For the dashboard
|
||||
on the domain of the current url. For the
|
||||
dashboard
|
||||
|
||||
this would mean the UI nginx would respond with
|
||||
|
||||
@ -5566,7 +5602,8 @@
|
||||
Be more lenient with decoding compressed responses,
|
||||
since (very rarely)
|
||||
|
||||
servers send slightly invalid gzip responses that are still accepted
|
||||
servers send slightly invalid gzip responses that are
|
||||
still accepted
|
||||
|
||||
by common browsers.
|
||||
|
||||
@ -7402,7 +7439,9 @@
|
||||
|
||||
```
|
||||
|
||||
Error: Could not detect abi for version 16.13.0 and runtime node. Updating "node-abi" might help solve this issue if it is a new release of node
|
||||
Error: Could not detect abi for version 16.13.0 and runtime
|
||||
node. Updating "node-abi" might help solve this issue if it is a new
|
||||
release of node
|
||||
|
||||
```
|
||||
footer:
|
||||
@ -7538,7 +7577,8 @@
|
||||
- getAllByApplication
|
||||
|
||||
|
||||
Changelog-entry: Enable audit logging and reviewing device changes. The SDK defaults to fetch last 7 days of history
|
||||
Changelog-entry: Enable audit logging and reviewing device
|
||||
changes. The SDK defaults to fetch last 7 days of history
|
||||
footer:
|
||||
Change-type: minor
|
||||
change-type: minor
|
||||
@ -7736,7 +7776,8 @@
|
||||
This is part of the work for enabling the creation of
|
||||
configuration
|
||||
|
||||
variables with a colon character as a means to allow Raspberry PI users
|
||||
variables with a colon character as a means to allow Raspberry
|
||||
PI users
|
||||
|
||||
to enable the second HDMI port on RPI4 and others.
|
||||
footer:
|
||||
@ -7896,11 +7937,14 @@
|
||||
[catch-uncommitted](https://github.com/resin-io-modules/catch-uncommitted)
|
||||
from 1.6.2 to 2.0.0.
|
||||
|
||||
- [Release notes](https://github.com/resin-io-modules/catch-uncommitted/releases)
|
||||
- [Release
|
||||
notes](https://github.com/resin-io-modules/catch-uncommitted/releases)
|
||||
|
||||
- [Changelog](https://github.com/balena-io-modules/catch-uncommitted/blob/master/CHANGELOG.md)
|
||||
-
|
||||
[Changelog](https://github.com/balena-io-modules/catch-uncommitted/blob/master/CHANGELOG.md)
|
||||
|
||||
- [Commits](https://github.com/resin-io-modules/catch-uncommitted/compare/v1.6.2...v2.0.0)
|
||||
-
|
||||
[Commits](https://github.com/resin-io-modules/catch-uncommitted/compare/v1.6.2...v2.0.0)
|
||||
|
||||
|
||||
---
|
||||
@ -8771,9 +8815,11 @@
|
||||
Bumps [parse-link-header](https://github.com/thlorenz/parse-link-header)
|
||||
from 1.0.1 to 2.0.0.
|
||||
|
||||
- [Release notes](https://github.com/thlorenz/parse-link-header/releases)
|
||||
- [Release
|
||||
notes](https://github.com/thlorenz/parse-link-header/releases)
|
||||
|
||||
- [Commits](https://github.com/thlorenz/parse-link-header/compare/v1.0.1...v2.0.0)
|
||||
-
|
||||
[Commits](https://github.com/thlorenz/parse-link-header/compare/v1.0.1...v2.0.0)
|
||||
|
||||
|
||||
---
|
||||
@ -9723,11 +9769,14 @@
|
||||
Bumps [browserify](https://github.com/browserify/browserify)
|
||||
from 14.5.0 to 17.0.0.
|
||||
|
||||
- [Release notes](https://github.com/browserify/browserify/releases)
|
||||
- [Release
|
||||
notes](https://github.com/browserify/browserify/releases)
|
||||
|
||||
- [Changelog](https://github.com/browserify/browserify/blob/master/changelog.markdown)
|
||||
-
|
||||
[Changelog](https://github.com/browserify/browserify/blob/master/changelog.markdown)
|
||||
|
||||
- [Commits](https://github.com/browserify/browserify/compare/14.5.0...v17.0.0)
|
||||
-
|
||||
[Commits](https://github.com/browserify/browserify/compare/14.5.0...v17.0.0)
|
||||
|
||||
|
||||
---
|
||||
@ -9755,9 +9804,11 @@
|
||||
|
||||
- [Release notes](https://github.com/raszi/node-tmp/releases)
|
||||
|
||||
- [Changelog](https://github.com/raszi/node-tmp/blob/master/CHANGELOG.md)
|
||||
-
|
||||
[Changelog](https://github.com/raszi/node-tmp/blob/master/CHANGELOG.md)
|
||||
|
||||
- [Commits](https://github.com/raszi/node-tmp/compare/v0.0.31...v0.2.1)
|
||||
-
|
||||
[Commits](https://github.com/raszi/node-tmp/compare/v0.0.31...v0.2.1)
|
||||
|
||||
|
||||
---
|
||||
@ -9839,9 +9890,11 @@
|
||||
|
||||
- [Release notes](https://github.com/mochajs/mocha/releases)
|
||||
|
||||
- [Changelog](https://github.com/mochajs/mocha/blob/master/CHANGELOG.md)
|
||||
-
|
||||
[Changelog](https://github.com/mochajs/mocha/blob/master/CHANGELOG.md)
|
||||
|
||||
- [Commits](https://github.com/mochajs/mocha/compare/v3.5.3...v10.0.0)
|
||||
-
|
||||
[Commits](https://github.com/mochajs/mocha/compare/v3.5.3...v10.0.0)
|
||||
|
||||
|
||||
---
|
||||
@ -9881,9 +9934,11 @@
|
||||
Bumps [mockttp](https://github.com/httptoolkit/mockttp) from
|
||||
0.9.1 to 2.7.0.
|
||||
|
||||
- [Release notes](https://github.com/httptoolkit/mockttp/releases)
|
||||
- [Release
|
||||
notes](https://github.com/httptoolkit/mockttp/releases)
|
||||
|
||||
- [Commits](https://github.com/httptoolkit/mockttp/compare/v0.9.1...v2.7.0)
|
||||
-
|
||||
[Commits](https://github.com/httptoolkit/mockttp/compare/v0.9.1...v2.7.0)
|
||||
|
||||
|
||||
---
|
||||
@ -9955,9 +10010,11 @@
|
||||
Bumps [superagent](https://github.com/visionmedia/superagent)
|
||||
from 3.8.3 to 7.1.2.
|
||||
|
||||
- [Release notes](https://github.com/visionmedia/superagent/releases)
|
||||
- [Release
|
||||
notes](https://github.com/visionmedia/superagent/releases)
|
||||
|
||||
- [Changelog](https://github.com/visionmedia/superagent/blob/master/HISTORY.md)
|
||||
-
|
||||
[Changelog](https://github.com/visionmedia/superagent/blob/master/HISTORY.md)
|
||||
|
||||
- [Commits](https://github.com/visionmedia/superagent/commits)
|
||||
|
||||
@ -9987,9 +10044,11 @@
|
||||
|
||||
- [Release notes](https://github.com/motdotla/dotenv/releases)
|
||||
|
||||
- [Changelog](https://github.com/motdotla/dotenv/blob/master/CHANGELOG.md)
|
||||
-
|
||||
[Changelog](https://github.com/motdotla/dotenv/blob/master/CHANGELOG.md)
|
||||
|
||||
- [Commits](https://github.com/motdotla/dotenv/compare/v4.0.0...v16.0.0)
|
||||
-
|
||||
[Commits](https://github.com/motdotla/dotenv/compare/v4.0.0...v16.0.0)
|
||||
|
||||
|
||||
---
|
||||
@ -10584,9 +10643,11 @@
|
||||
Using build instead of pull allows to add metadata (e.g. labels)
|
||||
to pulled images in an
|
||||
|
||||
atomic way. This commit adds the `DockerProgres.build()` method to
|
||||
atomic way. This commit adds the `DockerProgres.build()` method
|
||||
to
|
||||
|
||||
build an image from a remote (or local) source and track the progress of
|
||||
build an image from a remote (or local) source and track the
|
||||
progress of
|
||||
|
||||
the build.
|
||||
footer:
|
||||
@ -10617,7 +10678,8 @@
|
||||
body: >
|
||||
Starting in balenaOS v2.93.0 the supervisor images are tagged
|
||||
|
||||
as balena_supervisor after being pulled from the balena registry.
|
||||
as balena_supervisor after being pulled from the balena
|
||||
registry.
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
@ -11674,7 +11736,8 @@
|
||||
Be more lenient with decoding compressed
|
||||
responses, since (very rarely)
|
||||
|
||||
servers send slightly invalid gzip responses that are still accepted
|
||||
servers send slightly invalid gzip responses
|
||||
that are still accepted
|
||||
|
||||
by common browsers.
|
||||
|
||||
@ -13348,7 +13411,8 @@
|
||||
This changes improves the speed that the project is tarballed by
|
||||
switching from
|
||||
|
||||
`klaw` to `recursive-fs` and not running `lstat` on files that are ignored.
|
||||
`klaw` to `recursive-fs` and not running `lstat` on files that are
|
||||
ignored.
|
||||
|
||||
Whilst testing with the Jellyfish repository, which contains a number of
|
||||
|
||||
@ -13373,9 +13437,11 @@
|
||||
Fixes #2394
|
||||
|
||||
|
||||
When pushing to a device in local mode, if a service is not external, and uses
|
||||
When pushing to a device in local mode, if a service is not external,
|
||||
and uses
|
||||
|
||||
an `image` field, that value should be used for tags and target state, otherwise
|
||||
an `image` field, that value should be used for tags and target state,
|
||||
otherwise
|
||||
|
||||
it won't match the image name generated on the device by balenaEngine.
|
||||
footer:
|
||||
@ -13553,7 +13619,11 @@
|
||||
https://github.com/compose-spec/compose-spec/blob/43f6537b2c8f01b6d3f0e184d13a0f3cb93d38d7/spec.md#fragments
|
||||
|
||||
|
||||
Removing the FAILSAFE_SCHEMA flag is not expected to break existing project files, since the default behaviour is more liberal, or cause problems down the road given we perform validation immediately after. Docs for the flag: https://github.com/nodeca/js-yaml#load-string---options-
|
||||
Removing the FAILSAFE_SCHEMA flag is not expected to break existing
|
||||
project files, since the default behaviour is more liberal, or cause
|
||||
problems down the road given we perform validation immediately after.
|
||||
Docs for the flag:
|
||||
https://github.com/nodeca/js-yaml#load-string---options-
|
||||
footer:
|
||||
Change-type: minor
|
||||
change-type: minor
|
||||
@ -13860,7 +13930,8 @@
|
||||
Be more lenient with decoding compressed responses,
|
||||
since (very rarely)
|
||||
|
||||
servers send slightly invalid gzip responses that are still accepted
|
||||
servers send slightly invalid gzip responses that are
|
||||
still accepted
|
||||
|
||||
by common browsers.
|
||||
|
||||
@ -14159,7 +14230,8 @@
|
||||
This change allows use of a contract and release semver when doing a
|
||||
push,
|
||||
|
||||
and is part of the larger feature to use the builder as part of a CI/CD pipeline.
|
||||
and is part of the larger feature to use the builder as part of a CI/CD
|
||||
pipeline.
|
||||
footer:
|
||||
Change-type: minor
|
||||
change-type: minor
|
||||
@ -14610,7 +14682,8 @@
|
||||
body: >
|
||||
This change will allow to build releases as draft and have them being
|
||||
|
||||
set as final at a later stage. This change is part of a larger feature towards
|
||||
set as final at a later stage. This change is part of a larger feature
|
||||
towards
|
||||
|
||||
using the builder as part of CI/CD pipelines.
|
||||
footer:
|
||||
@ -15091,7 +15164,8 @@
|
||||
body: >
|
||||
When using deploy to create a release for a multi-container project one
|
||||
|
||||
needs to follow this to avoid triggering a build. Relevant for CI/CD scenarios
|
||||
needs to follow this to avoid triggering a build. Relevant for CI/CD
|
||||
scenarios
|
||||
|
||||
with their own build pipeline.
|
||||
footer:
|
||||
@ -15133,7 +15207,8 @@
|
||||
users to configure the image with system connection settings.
|
||||
|
||||
|
||||
This change affects both the `balena local configure` and `balena os configure` commands.
|
||||
This change affects both the `balena local configure` and `balena os
|
||||
configure` commands.
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
@ -15530,10 +15605,12 @@
|
||||
The `local` logging driver captures output from container’s
|
||||
stdout/stderr
|
||||
|
||||
and writes them to an internal storage that is optimized for performance and disk use.
|
||||
and writes them to an internal storage that is optimized for performance
|
||||
and disk use.
|
||||
|
||||
|
||||
We also want to capture these logs on startup to wait for success/failure.
|
||||
We also want to capture these logs on startup to wait for
|
||||
success/failure.
|
||||
|
||||
|
||||
Advise the use of `--privileged` when running Docker-in-Docker to avoid
|
||||
@ -15972,7 +16049,8 @@
|
||||
body: >
|
||||
10.4.0 improves image size estimation
|
||||
|
||||
10.4.1 prevents running out of space while pulling images because of temporary files
|
||||
10.4.1 prevents running out of space while pulling images because of
|
||||
temporary files
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
@ -24351,7 +24429,8 @@
|
||||
This fixes a build error caused by a recent version bump of
|
||||
'patch-package':
|
||||
|
||||
"Patch file found for package execa which is not present at node_modules/qqjs/node_modules/execa"
|
||||
"Patch file found for package execa which is not present at
|
||||
node_modules/qqjs/node_modules/execa"
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
@ -24636,7 +24715,8 @@
|
||||
any balenaOS devices' message - if the OS is Windows.
|
||||
|
||||
|
||||
Also updated the INSTALL instructions with details of the dependency on Bonjour.
|
||||
Also updated the INSTALL instructions with details of the dependency on
|
||||
Bonjour.
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
@ -25522,11 +25602,17 @@
|
||||
body: >
|
||||
The full warning output was:
|
||||
|
||||
(node:43572) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 drain listeners added. Use emitter.setMaxListeners() to increase limit
|
||||
(node:43572) MaxListenersExceededWarning: Possible EventEmitter memory
|
||||
leak detected. 11 drain listeners added. Use emitter.setMaxListeners()
|
||||
to increase limit
|
||||
|
||||
(node:43572) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 error listeners added. Use emitter.setMaxListeners() to increase limit
|
||||
(node:43572) MaxListenersExceededWarning: Possible EventEmitter memory
|
||||
leak detected. 11 error listeners added. Use emitter.setMaxListeners()
|
||||
to increase limit
|
||||
|
||||
(node:43572) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 close listeners added. Use emitter.setMaxListeners() to increase limit
|
||||
(node:43572) MaxListenersExceededWarning: Possible EventEmitter memory
|
||||
leak detected. 11 close listeners added. Use emitter.setMaxListeners()
|
||||
to increase limit
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
@ -25628,13 +25714,17 @@
|
||||
E.g. "balena build -e -h <IP> -p 2375" with the CLI running on a Mac
|
||||
laptop,
|
||||
|
||||
using balenaEngine on an Intel NUC device, building an image for the RPi (ARM
|
||||
using balenaEngine on an Intel NUC device, building an image for the RPi
|
||||
(ARM
|
||||
|
||||
image arch). Previously, QEMU setup by the CLI assumed that docker ran on the
|
||||
image arch). Previously, QEMU setup by the CLI assumed that docker ran
|
||||
on the
|
||||
|
||||
same OS as the CLI (Docker for Mac has built-in binfmt_misc support and does
|
||||
same OS as the CLI (Docker for Mac has built-in binfmt_misc support and
|
||||
does
|
||||
|
||||
not require additional setup, but balenaEngine on Linux requires explicit QEMU
|
||||
not require additional setup, but balenaEngine on Linux requires
|
||||
explicit QEMU
|
||||
|
||||
setup.)
|
||||
footer:
|
||||
@ -25725,7 +25815,8 @@
|
||||
Fixes #1380
|
||||
|
||||
|
||||
Argument parsing of "env rm" command was improved by migrating it to oclif
|
||||
Argument parsing of "env rm" command was improved by migrating it to
|
||||
oclif
|
||||
footer:
|
||||
Change-type: patch
|
||||
change-type: patch
|
||||
@ -25753,16 +25844,24 @@
|
||||
|
||||
```
|
||||
|
||||
lib/actions-oclif/env/add.ts(73,16): error TS2742: The inferred type of 'flags' cannot be named without a reference to '../../../../../../../../../volumes/live/c64feead-f78e-4bd4-742d-ccd29aef53c4/volume/node_modules/@oclif/parser/lib/flags'. This is likely not portable. A type annotation is necessary.
|
||||
lib/actions-oclif/env/add.ts(73,16): error TS2742: The inferred type of
|
||||
'flags' cannot be named without a reference to
|
||||
'../../../../../../../../../volumes/live/c64feead-f78e-4bd4-742d-ccd29aef53c4/volume/node_modules/@oclif/parser/lib/flags'.
|
||||
This is likely not portable. A type annotation is necessary.
|
||||
|
||||
lib/actions-oclif/version.ts(42,16): error TS2742: The inferred type of 'flags' cannot be named without a reference to '../../../../../../../../volumes/live/c64feead-f78e-4bd4-742d-ccd29aef53c4/volume/node_modules/@oclif/parser/lib/flags.js'. This is likely not portable. A type annotation is necessary.
|
||||
lib/actions-oclif/version.ts(42,16): error TS2742: The inferred type of
|
||||
'flags' cannot be named without a reference to
|
||||
'../../../../../../../../volumes/live/c64feead-f78e-4bd4-742d-ccd29aef53c4/volume/node_modules/@oclif/parser/lib/flags.js'.
|
||||
This is likely not portable. A type annotation is necessary.
|
||||
|
||||
```
|
||||
|
||||
|
||||
This appears to be reported on the Typescript repo here https://github.com/microsoft/TypeScript/issues/29221
|
||||
This appears to be reported on the Typescript repo here
|
||||
https://github.com/microsoft/TypeScript/issues/29221
|
||||
|
||||
The suggested workaround is to explicitly set the type of the `flags` static
|
||||
The suggested workaround is to explicitly set the type of the `flags`
|
||||
static
|
||||
|
||||
property.
|
||||
footer:
|
||||
@ -26817,7 +26916,8 @@
|
||||
To fix the same error as here
|
||||
https://github.com/nodejs/node/issues/20285
|
||||
|
||||
Task changes as described at https://fettblog.eu/gulp-4-parallel-and-series/
|
||||
Task changes as described at
|
||||
https://fettblog.eu/gulp-4-parallel-and-series/
|
||||
footers:
|
||||
change-type: patch
|
||||
signed-off-by: Gergely Imreh <gergely@balena.io>
|
||||
@ -27724,7 +27824,11 @@
|
||||
for is to determine whether the command should issue a legacy user API
|
||||
key or a provisioning key.
|
||||
|
||||
This makes version optional but tries to figure it out by itself by reading os-release from the image's boot partition. This is not foul-proof however, and while it'll work with most recent images it won't work with all and in that case it'll bail out and only then warn the user to specify it via the --version argument.
|
||||
This makes version optional but tries to figure it out by itself by
|
||||
reading os-release from the image's boot partition. This is not
|
||||
foul-proof however, and while it'll work with most recent images it
|
||||
won't work with all and in that case it'll bail out and only then warn
|
||||
the user to specify it via the --version argument.
|
||||
footers:
|
||||
change-type: minor
|
||||
hash: 8291c96e69407a4c691a35c27ff3cd406794e946
|
||||
@ -28364,9 +28468,21 @@
|
||||
compatibility merely by looking for the `os-config` executable in the
|
||||
device, and bail out if it’s not present.
|
||||
|
||||
`join` and `leave` accept a couple of optional arguments and implement a wizard-style interface if these are not given. They allow to interactively select the device and the application to promote to. If the user has no apps, `join` will offer the user to create one. `join` will also offer the user to login or create an account if they’re not logged in already without exiting the wizard.
|
||||
`join` and `leave` accept a couple of optional arguments and implement a
|
||||
wizard-style interface if these are not given. They allow to
|
||||
interactively select the device and the application to promote to. If
|
||||
the user has no apps, `join` will offer the user to create one. `join`
|
||||
will also offer the user to login or create an account if they’re not
|
||||
logged in already without exiting the wizard.
|
||||
|
||||
`resin-sync` (that's used internally to discover local devices) requires admin privileges. If no device has been specified as an argument, the commands will launch the device scanning process in a privileged subprocess via two new internal commands: `internal sudo` and `internal scanDevices`. This avoids having the user to invoke the commands with sudo and only request escalation if truly needed. This commit also removes the dependency to “president”, implementing “sudo” functionality within the CLI.
|
||||
`resin-sync` (that's used internally to discover local devices) requires
|
||||
admin privileges. If no device has been specified as an argument, the
|
||||
commands will launch the device scanning process in a privileged
|
||||
subprocess via two new internal commands: `internal sudo` and `internal
|
||||
scanDevices`. This avoids having the user to invoke the commands with
|
||||
sudo and only request escalation if truly needed. This commit also
|
||||
removes the dependency to “president”, implementing “sudo” functionality
|
||||
within the CLI.
|
||||
footers:
|
||||
change-type: minor
|
||||
hash: 5cbe1c410f7081ff78b41e8a6d9c0f06ad92934e
|
||||
@ -28835,7 +28951,8 @@
|
||||
image tars via the builder. It’s needed for users to avoid having to
|
||||
switch between CLI versions in order to push to legacy apps as well.
|
||||
|
||||
Note: this pins resin-sdk to 9.0.0-beta14 as I couldn’t get it to install otherwise — npm would always install 9.0.0-beta9 instead.
|
||||
Note: this pins resin-sdk to 9.0.0-beta14 as I couldn’t get it to
|
||||
install otherwise — npm would always install 9.0.0-beta9 instead.
|
||||
footers:
|
||||
change-type: minor
|
||||
hash: 62f006b89ab0fa8a1575f213579910f732f17c0f
|
||||
@ -28965,7 +29082,8 @@
|
||||
|
||||
* all 'resin-sdk' requires replaced with 'resin-sdk-preconfigured'
|
||||
|
||||
* resin-sdk-preconfigured TS typings are copy pasted from the current resin-sdk master
|
||||
* resin-sdk-preconfigured TS typings are copy pasted from the current
|
||||
resin-sdk master
|
||||
|
||||
The idea is to progressively replace all 'resin-sdk-preconfigured'
|
||||
|
||||
@ -29015,7 +29133,10 @@
|
||||
body: >-
|
||||
New version is 3.1.0.
|
||||
|
||||
The updated version is not backwards compatible as it removes all *Async methods that are in wide use in the CLI. The workaround for now is to manually promisify the client and replace all `new Docker()` calls with a shared function that returns a promisified client.
|
||||
The updated version is not backwards compatible as it removes all *Async
|
||||
methods that are in wide use in the CLI. The workaround for now is to
|
||||
manually promisify the client and replace all `new Docker()` calls with
|
||||
a shared function that returns a promisified client.
|
||||
hash: 299bc0db132e5b04894b6b955aa469666a66ce8c
|
||||
subject: Update docker-toolbelt
|
||||
- author: Akis Kesoglou
|
||||
@ -29040,9 +29161,11 @@
|
||||
|
||||
- Adds a utility file to retrieve the CLI version and its parts
|
||||
|
||||
- Adds a helper that can be used to manipulate display on capable clients
|
||||
- Adds a helper that can be used to manipulate display on capable
|
||||
clients
|
||||
|
||||
- Declares several new dependencies. Most are already indirectly installed via some dependency
|
||||
- Declares several new dependencies. Most are already indirectly
|
||||
installed via some dependency
|
||||
footers:
|
||||
change-type: minor
|
||||
hash: 14a3f51b730b12ad66462342888fb2b4bcf1f1ea
|
||||
|
@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file
|
||||
automatically by Versionist. DO NOT EDIT THIS FILE MANUALLY!
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## 18.0.2 - 2024-03-07
|
||||
|
||||
* Remove no longer needed windows oclif patches [Otavio Jacobi]
|
||||
|
||||
## 18.0.1 - 2024-03-07
|
||||
|
||||
* Fix windows signing [Otavio Jacobi]
|
||||
|
||||
## 18.0.0 - 2024-02-06
|
||||
|
||||
* Update to Node 20 [Otávio Jacobi]
|
||||
|
@ -435,18 +435,20 @@ async function renameInstallerFiles() {
|
||||
* https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe
|
||||
*/
|
||||
async function signWindowsInstaller() {
|
||||
if (process.env.CSC_LINK && process.env.CSC_KEY_PASSWORD) {
|
||||
if (process.env.SM_CODE_SIGNING_CERT_SHA1_HASH) {
|
||||
const exeName = renamedOclifInstallers[process.platform];
|
||||
console.log(`Signing installer "${exeName}"`);
|
||||
// trust ...
|
||||
await execFileAsync('signtool.exe', [
|
||||
'sign',
|
||||
'-t',
|
||||
'-sha1',
|
||||
process.env.SM_CODE_SIGNING_CERT_SHA1_HASH,
|
||||
'-tr',
|
||||
process.env.TIMESTAMP_SERVER || 'http://timestamp.comodoca.com',
|
||||
'-f',
|
||||
process.env.CSC_LINK,
|
||||
'-p',
|
||||
process.env.CSC_KEY_PASSWORD,
|
||||
'-td',
|
||||
'SHA256',
|
||||
'-fd',
|
||||
'SHA256',
|
||||
'-d',
|
||||
`balena-cli ${version}`,
|
||||
exeName,
|
||||
|
@ -1,74 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2016-2020 Balena Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import { stripIndent } from '../../utils/lazy';
|
||||
import { CommandHelp } from '../../utils/oclif-utils';
|
||||
|
||||
// 'Internal' commands are called during the execution of other commands.
|
||||
// `osinit` is called during `os initialize`
|
||||
// TODO: These should be refactored to modules/functions, and removed
|
||||
// See previous `internal sudo` refactor:
|
||||
// - https://github.com/balena-io/balena-cli/pull/1455/files
|
||||
// - https://github.com/balena-io/balena-cli/pull/1455#discussion_r334308357
|
||||
// - https://github.com/balena-io/balena-cli/pull/1455#discussion_r334308526
|
||||
|
||||
export default class OsinitCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Do actual init of the device with the preconfigured os image.
|
||||
|
||||
Don't use this command directly!
|
||||
Use \`balena os initialize <image>\` instead.
|
||||
`;
|
||||
|
||||
public static args = {
|
||||
image: Args.string({
|
||||
required: true,
|
||||
}),
|
||||
type: Args.string({
|
||||
required: true,
|
||||
}),
|
||||
config: Args.string({
|
||||
required: true,
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = (
|
||||
'internal osinit ' +
|
||||
new CommandHelp({ args: OsinitCmd.args }).defaultUsage()
|
||||
).trim();
|
||||
|
||||
public static hidden = true;
|
||||
public static root = true;
|
||||
public static offlineCompatible = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params } = await this.parse(OsinitCmd);
|
||||
|
||||
const config = JSON.parse(params.config);
|
||||
|
||||
const { getManifest, osProgressHandler } = await import(
|
||||
'../../utils/helpers'
|
||||
);
|
||||
const manifest = await getManifest(params.image, params.type);
|
||||
|
||||
const { initialize } = await import('balena-device-init');
|
||||
const initializeEmitter = await initialize(params.image, manifest, config);
|
||||
await osProgressHandler(initializeEmitter);
|
||||
}
|
||||
}
|
@ -29,9 +29,20 @@ import {
|
||||
devModeInfo,
|
||||
secureBootInfo,
|
||||
} from '../../utils/messages';
|
||||
import { ImgConfig } from '../../utils/config';
|
||||
|
||||
const CONNECTIONS_FOLDER = '/system-connections';
|
||||
|
||||
type DeviceConfigDefinition = {
|
||||
partition: number | { logical: number, primary: number },
|
||||
image?: string,
|
||||
path?: string
|
||||
};
|
||||
|
||||
type Manifest = BalenaSdk.DeviceTypeJson.DeviceType & {
|
||||
configuration?: { config?: DeviceConfigDefinition }
|
||||
};
|
||||
|
||||
type FlagsDef = Interfaces.InferredFlags<typeof OsConfigureCmd.flags>;
|
||||
|
||||
interface Answers {
|
||||
@ -172,7 +183,6 @@ export default class OsConfigureCmd extends Command {
|
||||
|
||||
await validateOptions(options);
|
||||
|
||||
const devInit = await import('balena-device-init');
|
||||
const { promises: fs } = await import('fs');
|
||||
const { generateDeviceConfig, generateApplicationConfig } = await import(
|
||||
'../../utils/config'
|
||||
@ -219,11 +229,10 @@ export default class OsConfigureCmd extends Command {
|
||||
const { normalizeOsVersion } = await import('../../utils/normalization');
|
||||
const osVersion = normalizeOsVersion(
|
||||
options.version ||
|
||||
(await getOsVersionFromImage(
|
||||
params.image,
|
||||
deviceTypeManifest,
|
||||
devInit,
|
||||
)),
|
||||
(await getOsVersionFromImage(
|
||||
params.image,
|
||||
deviceTypeManifest,
|
||||
)),
|
||||
);
|
||||
|
||||
const { validateDevOptionAndWarn } = await import('../../utils/config');
|
||||
@ -270,13 +279,11 @@ export default class OsConfigureCmd extends Command {
|
||||
console.info('Configuring operating system image');
|
||||
|
||||
const image = params.image;
|
||||
await helpers.osProgressHandler(
|
||||
await devInit.configure(
|
||||
image,
|
||||
deviceTypeManifest,
|
||||
configJson || {},
|
||||
answers,
|
||||
),
|
||||
await addConfigurationToImage(
|
||||
image,
|
||||
deviceTypeManifest,
|
||||
configJson || {},
|
||||
answers,
|
||||
);
|
||||
|
||||
if (options['system-connection']) {
|
||||
@ -312,6 +319,21 @@ export default class OsConfigureCmd extends Command {
|
||||
}
|
||||
}
|
||||
|
||||
async function addConfigurationToImage(
|
||||
image: string,
|
||||
manifest: Manifest,
|
||||
config: ImgConfig | object,
|
||||
answers: Answers,
|
||||
) {
|
||||
// TODO: check if manifest.yocto.image check is needed...
|
||||
const osVersion = await getOsVersionFromImage(image, manifest);
|
||||
const bSemver = await import('balena-semver');
|
||||
const major = bSemver.major(osVersion);
|
||||
convertFilePathDefinition(manifest.configuration?.config);
|
||||
|
||||
console.log(image, manifest, config, answers);
|
||||
}
|
||||
|
||||
async function validateOptions(options: FlagsDef) {
|
||||
// The 'device' and 'application' options are declared "exclusive" in the oclif
|
||||
// flag definitions above, so oclif will enforce that they are not both used together.
|
||||
@ -329,6 +351,29 @@ async function validateOptions(options: FlagsDef) {
|
||||
await Command.checkLoggedIn();
|
||||
}
|
||||
|
||||
async function definitionForImage(imagePath: string, configDefinition: DeviceConfigDefinition) {
|
||||
const definition = _.cloneDeep(configDefinition)
|
||||
if (configDefinition.image != null) {
|
||||
const path = await import('path');
|
||||
definition.image = path.join(imagePath, configDefinition.image);
|
||||
} else {
|
||||
definition.image = imagePath;
|
||||
}
|
||||
return definition;
|
||||
};
|
||||
|
||||
function convertFilePathDefinition(configDefinition: DeviceConfigDefinition) {
|
||||
const definition = _.cloneDeep(configDefinition);
|
||||
if (_.isObject(definition.partition)) {
|
||||
if (definition.partition.logical != null) {
|
||||
definition.partition = definition.partition.logical + 4;
|
||||
} else {
|
||||
definition.partition = definition.partition.primary;
|
||||
}
|
||||
}
|
||||
return definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around balena-device-init.getImageOsVersion(). Throws ExpectedError
|
||||
* if the OS image could not be read or the OS version could not be extracted
|
||||
@ -338,13 +383,38 @@ async function validateOptions(options: FlagsDef) {
|
||||
*/
|
||||
async function getOsVersionFromImage(
|
||||
imagePath: string,
|
||||
deviceTypeManifest: BalenaSdk.DeviceTypeJson.DeviceType,
|
||||
devInit: typeof import('balena-device-init'),
|
||||
deviceTypeManifest: Manifest,
|
||||
): Promise<string> {
|
||||
const osVersion = await devInit.getImageOsVersion(
|
||||
imagePath,
|
||||
deviceTypeManifest,
|
||||
);
|
||||
|
||||
// TODO: check if all this is needed or if we can just assume { patition: 1 } for all
|
||||
const config = deviceTypeManifest?.configuration?.config ?? { partition: 1 };
|
||||
const definition = convertFilePathDefinition(await definitionForImage(imagePath, config));
|
||||
definition.path = '/os-release';
|
||||
|
||||
const imagefs = await import('balena-image-fs');
|
||||
const osReleaseString = await imagefs.interact(definition.image as string, definition.partition as number, (fs) => {
|
||||
return promisify(fs.readFile)(definition.path as string, { encoding: 'utf8' });
|
||||
});
|
||||
|
||||
const parsedOsRelease = _(osReleaseString)
|
||||
.split('\n')
|
||||
.map((line) => {
|
||||
const match = line.match(/(.*)=(.*)/);
|
||||
if (match) {
|
||||
return [
|
||||
match[1],
|
||||
match[2].replace(/^"(.*)"$/, '$1').replace(/^'(.*)'$/, '$1')
|
||||
]
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.filter()
|
||||
.fromPairs()
|
||||
.value();
|
||||
|
||||
const osVersion = parsedOsRelease.NAME !== 'Resin OS' && parsedOsRelease.NAME !== 'balenaOS' ? null : parsedOsRelease.VERSION;
|
||||
|
||||
if (!osVersion) {
|
||||
throw new ExpectedError(stripIndent`
|
||||
Could not read OS version from the image. Please specify the balenaOS
|
||||
|
@ -1,102 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2016-2021 Balena Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { Args } from '@oclif/core';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getCliForm, stripIndent } from '../../utils/lazy';
|
||||
|
||||
const INIT_WARNING_MESSAGE = `
|
||||
|
||||
Note: Initializing the device may ask for administrative permissions
|
||||
because we need to access the raw devices directly.\
|
||||
`;
|
||||
|
||||
export default class OsInitializeCmd extends Command {
|
||||
public static description = stripIndent`
|
||||
Initialize an os image for a device.
|
||||
|
||||
Initialize an os image for a device with a previously
|
||||
configured operating system image and flash the
|
||||
an external storage drive or the device's storage
|
||||
medium depending on the device type.
|
||||
${INIT_WARNING_MESSAGE}
|
||||
`;
|
||||
|
||||
public static examples = [
|
||||
'$ balena os initialize ../path/rpi.img --type raspberry-pi',
|
||||
];
|
||||
|
||||
public static args = {
|
||||
image: Args.string({
|
||||
description: 'path to OS image',
|
||||
required: true,
|
||||
}),
|
||||
};
|
||||
|
||||
public static usage = 'os initialize <image>';
|
||||
|
||||
public static flags = {
|
||||
type: cf.deviceType,
|
||||
drive: cf.drive,
|
||||
yes: cf.yes,
|
||||
help: cf.help,
|
||||
};
|
||||
|
||||
public static authenticated = true;
|
||||
|
||||
public async run() {
|
||||
const { args: params, flags: options } = await this.parse(OsInitializeCmd);
|
||||
|
||||
const { getManifest, sudo } = await import('../../utils/helpers');
|
||||
|
||||
console.info(`Initializing device ${INIT_WARNING_MESSAGE}`);
|
||||
|
||||
const manifest = await getManifest(params.image, options.type);
|
||||
|
||||
const answers = await getCliForm().run(manifest.initialization?.options, {
|
||||
override: {
|
||||
drive: options.drive,
|
||||
},
|
||||
});
|
||||
|
||||
if (answers.drive != null) {
|
||||
const { confirm } = await import('../../utils/patterns');
|
||||
await confirm(
|
||||
options.yes,
|
||||
`This will erase ${answers.drive}. Are you sure?`,
|
||||
`Going to erase ${answers.drive}.`,
|
||||
);
|
||||
const { safeUmount } = await import('../../utils/umount');
|
||||
await safeUmount(answers.drive);
|
||||
}
|
||||
|
||||
await sudo([
|
||||
'internal',
|
||||
'osinit',
|
||||
params.image,
|
||||
options.type,
|
||||
JSON.stringify(answers),
|
||||
]);
|
||||
|
||||
if (answers.drive != null) {
|
||||
const { safeUmount } = await import('../../utils/umount');
|
||||
await safeUmount(answers.drive);
|
||||
console.info(`You can safely remove ${answers.drive} now`);
|
||||
}
|
||||
}
|
||||
}
|
@ -14,13 +14,13 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import type { InitializeEmitter, OperationState } from 'balena-device-init';
|
||||
import type * as BalenaSdk from 'balena-sdk';
|
||||
|
||||
import * as _ from 'lodash';
|
||||
import * as os from 'node:os';
|
||||
import { promisify } from 'util';
|
||||
|
||||
import { getBalenaSdk, getChalk, getVisuals } from './lazy';
|
||||
import { getBalenaSdk } from './lazy';
|
||||
|
||||
export function getGroupDefaults(group: {
|
||||
options: Array<{ name: string; default: string | number }>;
|
||||
@ -32,25 +32,6 @@ export function getGroupDefaults(group: {
|
||||
.value();
|
||||
}
|
||||
|
||||
export function stateToString(state: OperationState) {
|
||||
const percentage = _.padStart(`${state.percentage}`, 3, '0');
|
||||
const chalk = getChalk();
|
||||
const result = `${chalk.blue(percentage + '%')} ${chalk.cyan(
|
||||
state.operation.command,
|
||||
)}`;
|
||||
|
||||
switch (state.operation.command) {
|
||||
case 'copy':
|
||||
return `${result} ${state.operation.from.path} -> ${state.operation.to.path}`;
|
||||
case 'replace':
|
||||
return `${result} ${state.operation.file.path}, ${state.operation.copy} -> ${state.operation.replace}`;
|
||||
case 'run-script':
|
||||
return `${result} ${state.operation.script}`;
|
||||
default:
|
||||
throw new Error(`Unsupported operation: ${state.operation.command}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a child process with admin / superuser privileges, prompting the user for
|
||||
* elevation as needed, and taking care of shell-escaping arguments in a suitable way
|
||||
@ -107,9 +88,17 @@ export async function getManifest(
|
||||
image: string,
|
||||
deviceType: string,
|
||||
): Promise<BalenaSdk.DeviceTypeJson.DeviceType> {
|
||||
const init = await import('balena-device-init');
|
||||
const sdk = getBalenaSdk();
|
||||
const manifest = await init.getImageManifest(image);
|
||||
|
||||
const imagefs = await import ('balena-image-fs');
|
||||
const manifest = await imagefs.interact(image, 1, async (fs) => {
|
||||
const readFileAsync = promisify(fs.readFile);
|
||||
const manifest = await readFileAsync('/device-type.json', {
|
||||
encoding: 'utf8',
|
||||
});
|
||||
return JSON.parse(manifest) as BalenaSdk.DeviceTypeJson.DeviceType;
|
||||
});
|
||||
|
||||
if (
|
||||
manifest != null &&
|
||||
manifest.slug !== deviceType &&
|
||||
@ -126,6 +115,13 @@ export async function getManifest(
|
||||
);
|
||||
}
|
||||
|
||||
export function getOperatingSystem():
|
||||
| Exclude<NodeJS.Platform, 'darwin'>
|
||||
| 'osx' {
|
||||
const platform = os.platform();
|
||||
return platform === 'darwin' ? 'osx' : platform;
|
||||
}
|
||||
|
||||
export const areDeviceTypesCompatible = async (
|
||||
appDeviceTypeSlug: string,
|
||||
osDeviceTypeSlug: string,
|
||||
@ -156,31 +152,6 @@ export const areDeviceTypesCompatible = async (
|
||||
);
|
||||
};
|
||||
|
||||
export async function osProgressHandler(step: InitializeEmitter) {
|
||||
step.on('stdout', process.stdout.write.bind(process.stdout));
|
||||
step.on('stderr', process.stderr.write.bind(process.stderr));
|
||||
|
||||
step.on('state', function (state) {
|
||||
if (state.operation.command === 'burn') {
|
||||
return;
|
||||
}
|
||||
console.log(exports.stateToString(state));
|
||||
});
|
||||
|
||||
const visuals = getVisuals();
|
||||
const progressBars = {
|
||||
write: new visuals.Progress('Writing Device OS'),
|
||||
check: new visuals.Progress('Validating Device OS'),
|
||||
};
|
||||
|
||||
step.on('burn', (state) => progressBars[state.type].update(state));
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
step.on('error', reject);
|
||||
step.on('end' as any, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
export async function getAppWithArch(applicationName: string) {
|
||||
const { getApplication } = await import('./sdk');
|
||||
const balena = getBalenaSdk();
|
||||
|
1092
npm-shrinkwrap.json
generated
1092
npm-shrinkwrap.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "balena-cli",
|
||||
"version": "18.0.0",
|
||||
"version": "18.0.2",
|
||||
"description": "The official balena Command Line Interface",
|
||||
"main": "./build/app.js",
|
||||
"homepage": "https://github.com/balena-io/balena-cli",
|
||||
@ -206,9 +206,8 @@
|
||||
"@types/update-notifier": "^4.1.1",
|
||||
"@yao-pkg/pkg": "^5.11.1",
|
||||
"balena-config-json": "^4.2.0",
|
||||
"balena-device-init": "^6.0.0",
|
||||
"balena-errors": "^4.7.3",
|
||||
"balena-image-fs": "^7.0.6",
|
||||
"balena-image-fs": "^7.2.2",
|
||||
"balena-image-manager": "^10.0.1",
|
||||
"balena-preload": "^15.0.1",
|
||||
"balena-sdk": "^19.4.0",
|
||||
@ -286,6 +285,6 @@
|
||||
"windosu": "^0.3.0"
|
||||
},
|
||||
"versionist": {
|
||||
"publishedAt": "2024-02-06T12:19:36.007Z"
|
||||
"publishedAt": "2024-03-07T19:40:23.419Z"
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ index d06d0b3..c571fe3 100644
|
||||
const arches = _.uniq(buildConfig.targets
|
||||
.filter(t => t.platform === 'darwin')
|
||||
diff --git a/node_modules/oclif/lib/commands/pack/win.js b/node_modules/oclif/lib/commands/pack/win.js
|
||||
index c0926bd..a37cd6e 100644
|
||||
index c0926bd..e4f645c 100644
|
||||
--- a/node_modules/oclif/lib/commands/pack/win.js
|
||||
+++ b/node_modules/oclif/lib/commands/pack/win.js
|
||||
@@ -59,6 +59,12 @@ InstallDir "\$PROGRAMFILES${arch === 'x64' ? '64' : ''}\\${config.dirname}"
|
||||
@ -29,18 +29,8 @@ index c0926bd..a37cd6e 100644
|
||||
SetOutPath $INSTDIR
|
||||
File /r bin
|
||||
File /r client
|
||||
@@ -226,7 +232,8 @@ class PackWin extends core_1.Command {
|
||||
fs.writeFile(path.join(installerBase, 'bin', `${flags['additional-cli']}`), scripts.sh({ bin: flags['additional-cli'] })),
|
||||
] : []));
|
||||
await fs.move(buildConfig.workspace({ platform: 'win32', arch }), path.join(installerBase, 'client'));
|
||||
- await exec(`makensis ${installerBase}/${config.bin}.nsi | grep -v "\\[compress\\]" | grep -v "^File: Descending to"`);
|
||||
+ const { msysExec, toMsysPath } = require("../../util");
|
||||
+ await msysExec(`makensis ${toMsysPath(installerBase)}/${config.bin}.nsi | grep -v "\\[compress\\]" | grep -v "^File: Descending to"`);
|
||||
const templateKey = (0, upload_util_1.templateShortKey)('win32', { bin: config.bin, version: config.version, sha: buildConfig.gitSha, arch });
|
||||
const o = buildConfig.dist(`win32/${templateKey}`);
|
||||
await fs.move(path.join(installerBase, 'installer.exe'), o);
|
||||
diff --git a/node_modules/oclif/lib/tarballs/build.js b/node_modules/oclif/lib/tarballs/build.js
|
||||
index 384ea4b..602daa4 100644
|
||||
index 384ea4b..72ad66f 100644
|
||||
--- a/node_modules/oclif/lib/tarballs/build.js
|
||||
+++ b/node_modules/oclif/lib/tarballs/build.js
|
||||
@@ -21,7 +21,8 @@ const pack = async (from, to) => {
|
||||
@ -53,17 +43,18 @@ index 384ea4b..602daa4 100644
|
||||
const packCLI = async () => {
|
||||
const { stdout } = await exec('npm pack --unsafe-perm', { cwd: c.root });
|
||||
return path.join(c.root, stdout.trim().split('\n').pop());
|
||||
@@ -30,7 +31,8 @@ async function build(c, options = {}) {
|
||||
@@ -30,7 +31,9 @@ async function build(c, options = {}) {
|
||||
await fs.emptyDir(c.workspace());
|
||||
const tarballNewLocation = path.join(c.workspace(), path.basename(tarball));
|
||||
await fs.move(tarball, tarballNewLocation);
|
||||
- await exec(`tar -xzf "${tarballNewLocation}"`, { cwd: c.workspace() });
|
||||
+ const { msysExec, toMsysPath } = require("../util");
|
||||
+ await msysExec(`tar -xzf ${toMsysPath(tarballNewLocation)}`, { cwd: c.workspace() });
|
||||
+ let tarCmd = `tar -xzf "${tarballNewLocation}"`;
|
||||
+ if (process.platform === 'win32') tarCmd += ' --force-local';
|
||||
+ await exec(tarCmd, { cwd: c.workspace() });
|
||||
await Promise.all((await fs.promises.readdir(path.join(c.workspace(), 'package'), { withFileTypes: true }))
|
||||
.map(i => fs.move(path.join(c.workspace(), 'package', i.name), path.join(c.workspace(), i.name))));
|
||||
await Promise.all([
|
||||
@@ -38,6 +40,13 @@ async function build(c, options = {}) {
|
||||
@@ -38,6 +41,13 @@ async function build(c, options = {}) {
|
||||
fs.promises.rm(path.join(c.workspace(), path.basename(tarball)), { recursive: true }),
|
||||
fs.remove(path.join(c.workspace(), 'bin', 'run.cmd')),
|
||||
]);
|
||||
@ -77,7 +68,7 @@ index 384ea4b..602daa4 100644
|
||||
};
|
||||
const updatePJSON = async () => {
|
||||
const pjsonPath = path.join(c.workspace(), 'package.json');
|
||||
@@ -49,35 +58,20 @@ async function build(c, options = {}) {
|
||||
@@ -49,35 +59,20 @@ async function build(c, options = {}) {
|
||||
await fs.writeJSON(pjsonPath, pjson, { spaces: 2 });
|
||||
};
|
||||
const addDependencies = async () => {
|
||||
@ -126,7 +117,7 @@ index 384ea4b..602daa4 100644
|
||||
};
|
||||
const pretarball = async () => {
|
||||
const pjson = await fs.readJSON(path.join(c.workspace(), 'package.json'));
|
||||
@@ -115,7 +109,8 @@ async function build(c, options = {}) {
|
||||
@@ -115,7 +110,8 @@ async function build(c, options = {}) {
|
||||
output: path.join(workspace, 'bin', 'node'),
|
||||
platform: target.platform,
|
||||
arch: target.arch,
|
||||
@ -136,7 +127,7 @@ index 384ea4b..602daa4 100644
|
||||
});
|
||||
if (options.pack === false)
|
||||
return;
|
||||
@@ -158,6 +153,7 @@ async function build(c, options = {}) {
|
||||
@@ -158,6 +154,7 @@ async function build(c, options = {}) {
|
||||
await fs.writeJSON(manifestFilepath, manifest, { spaces: 2 });
|
||||
};
|
||||
(0, log_1.log)(`gathering workspace for ${config.bin} to ${c.workspace()}`);
|
||||
@ -169,40 +160,6 @@ index 216759d..cab0e6e 100644
|
||||
if (target && target.platform)
|
||||
return path.join(base, [target.platform, target.arch].join('-'), (0, upload_util_1.templateShortKey)('baseDir', { bin: config.bin }));
|
||||
return path.join(base, (0, upload_util_1.templateShortKey)('baseDir', { bin: config.bin }));
|
||||
diff --git a/node_modules/oclif/lib/tarballs/node.js b/node_modules/oclif/lib/tarballs/node.js
|
||||
index 35f1d0c..5349eaa 100644
|
||||
--- a/node_modules/oclif/lib/tarballs/node.js
|
||||
+++ b/node_modules/oclif/lib/tarballs/node.js
|
||||
@@ -12,6 +12,7 @@ const retry = require("async-retry");
|
||||
const util_2 = require("../util");
|
||||
const pipeline = (0, util_1.promisify)(stream_1.pipeline);
|
||||
const exec = (0, util_1.promisify)(child_process_1.exec);
|
||||
+const { isMSYS2, msysExec, toMsysPath } = require("../util");
|
||||
const RETRY_TIMEOUT_MS = 1000;
|
||||
async function fetchNodeBinary({ nodeVersion, output, platform, arch, tmp }) {
|
||||
if (arch === 'arm')
|
||||
@@ -42,8 +43,10 @@ async function fetchNodeBinary({ nodeVersion, output, platform, arch, tmp }) {
|
||||
const basedir = path.dirname(tarball);
|
||||
await fs.promises.mkdir(basedir, { recursive: true });
|
||||
await pipeline(got_1.default.stream(url), fs.createWriteStream(tarball));
|
||||
- if (platform !== 'win32')
|
||||
- await exec(`grep "${path.basename(tarball)}" "${shasums}" | shasum -a 256 -c -`, { cwd: basedir });
|
||||
+ if (platform !== 'win32') {
|
||||
+ const shaCmd = isMSYS2 ? 'sha256sum -c -' : 'shasum -a 256 -c -';
|
||||
+ await msysExec(`grep ${path.basename(tarball)} ${toMsysPath(shasums)} | ${shaCmd}`, { cwd: basedir });
|
||||
+ }
|
||||
};
|
||||
const extract = async () => {
|
||||
(0, log_1.log)(`extracting ${nodeBase}`);
|
||||
@@ -51,7 +54,7 @@ async function fetchNodeBinary({ nodeVersion, output, platform, arch, tmp }) {
|
||||
await fs.promises.mkdir(nodeTmp, { recursive: true });
|
||||
await fs.promises.mkdir(path.dirname(cache), { recursive: true });
|
||||
if (platform === 'win32') {
|
||||
- await exec(`7z x -bd -y "${tarball}"`, { cwd: nodeTmp });
|
||||
+ await msysExec(`7z x -bd -y ${toMsysPath(tarball)} > /dev/null`, { cwd: nodeTmp });
|
||||
await fs.move(path.join(nodeTmp, nodeBase, 'node.exe'), path.join(cache, 'node.exe'));
|
||||
}
|
||||
else {
|
||||
diff --git a/node_modules/oclif/lib/upload-util.js b/node_modules/oclif/lib/upload-util.js
|
||||
index 6963e4d..430472d 100644
|
||||
--- a/node_modules/oclif/lib/upload-util.js
|
||||
@ -222,64 +179,3 @@ index 6963e4d..430472d 100644
|
||||
deb: '<%- bin %>_<%- versionShaRevision %>_<%- arch %>.deb',
|
||||
};
|
||||
return _.template(templates[type])(Object.assign({}, options));
|
||||
diff --git a/node_modules/oclif/lib/util.js b/node_modules/oclif/lib/util.js
|
||||
index 816c71b..1384aa6 100644
|
||||
--- a/node_modules/oclif/lib/util.js
|
||||
+++ b/node_modules/oclif/lib/util.js
|
||||
@@ -95,9 +95,10 @@ const hash = async (algo, fp) => {
|
||||
});
|
||||
};
|
||||
exports.hash = hash;
|
||||
+
|
||||
async function checkFor7Zip() {
|
||||
try {
|
||||
- await exec('7z');
|
||||
+ await msysExec('7z', { stdio: [0, null, 2] });
|
||||
}
|
||||
catch (error) {
|
||||
if (error.code === 127)
|
||||
@@ -107,3 +108,44 @@ async function checkFor7Zip() {
|
||||
}
|
||||
}
|
||||
exports.checkFor7Zip = checkFor7Zip;
|
||||
+
|
||||
+// OSTYPE is 'msys' for MSYS 1.0 and for MSYS2, or 'cygwin' for Cygwin
|
||||
+// but note that OSTYPE is not "exported" by default, so run: export OSTYPE=$OSTYPE
|
||||
+// MSYSTEM is 'MINGW32' for MSYS 1.0, 'MSYS' for MSYS2, and undefined for Cygwin
|
||||
+const isCygwin = process.env.OSTYPE === 'cygwin';
|
||||
+const isMinGW = process.env.MSYSTEM && process.env.MSYSTEM.startsWith('MINGW');
|
||||
+const isMSYS2 = process.env.MSYSTEM && process.env.MSYSTEM.startsWith('MSYS');
|
||||
+const MSYSSHELLPATH = process.env.MSYSSHELLPATH ||
|
||||
+ (isMSYS2 ? 'C:\\msys64\\usr\\bin\\bash.exe' :
|
||||
+ (isMinGW ? 'C:\\MinGW\\msys\\1.0\\bin\\bash.exe' :
|
||||
+ (isCygwin ? 'C:\\cygwin64\\bin\\bash.exe' : '/bin/sh')));
|
||||
+
|
||||
+exports.isCygwin = isCygwin;
|
||||
+exports.isMinGW = isMinGW;
|
||||
+exports.isMSYS2 = isMSYS2;
|
||||
+console.error(`[debug] oclif MSYSSHELLPATH=${MSYSSHELLPATH} MSYSTEM=${process.env.MSYSTEM} OSTYPE=${process.env.OSTYPE} isMSYS2=${isMSYS2} isMingGW=${isMinGW} isCygwin=${isCygwin}`);
|
||||
+
|
||||
+/* Convert a Windows path like 'C:\tmp' to a MSYS path like '/c/tmp' */
|
||||
+function toMsysPath(windowsPath) {
|
||||
+ // 'c:\myfolder' -> '/c/myfolder' or '/cygdrive/c/myfolder'
|
||||
+ let msysPath = windowsPath.replace(/\\/g, '/');
|
||||
+ if (isMSYS2 || isMinGW) {
|
||||
+ msysPath = msysPath.replace(/^([a-zA-Z]):/, '/$1');
|
||||
+ } else if (isCygwin) {
|
||||
+ msysPath = msysPath.replace(/^([a-zA-Z]):/, '/cygdrive/$1');
|
||||
+ }
|
||||
+ console.error(`[debug] oclif toMsysPath before="${windowsPath}" after="${msysPath}"`);
|
||||
+ return msysPath;
|
||||
+}
|
||||
+exports.toMsysPath = toMsysPath;
|
||||
+
|
||||
+async function msysExec(cmd, options = {}) {
|
||||
+ if (process.platform !== 'win32') {
|
||||
+ return exec(cmd, options);
|
||||
+ }
|
||||
+ const sh = MSYSSHELLPATH;
|
||||
+ const args = ['-c', cmd];
|
||||
+ console.error(`[debug] oclif msysExec sh="${sh}" args=${JSON.stringify(args)} options=${JSON.stringify(options)}`);
|
||||
+ return exec(`"${sh}" "${args.join('" "')}"`, options);
|
||||
+}
|
||||
+exports.msysExec = msysExec;
|
||||
|
@ -66,7 +66,6 @@ describe('detectEncoding() function', function () {
|
||||
'mountutils/build/Release/MountUtils.node',
|
||||
];
|
||||
const sampleText = [
|
||||
'node_modules/.bin/etcher-image-write',
|
||||
'node_modules/.bin/mocha',
|
||||
'node_modules/.bin/rimraf',
|
||||
'node_modules/.bin/tsc',
|
||||
|
102
typings/balena-device-init/index.d.ts
vendored
102
typings/balena-device-init/index.d.ts
vendored
@ -1,102 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2019 Balena Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
declare module 'balena-device-init' {
|
||||
import { DeviceTypeJson } from 'balena-sdk';
|
||||
import * as Bluebird from 'bluebird';
|
||||
|
||||
interface OperationState {
|
||||
operation:
|
||||
| CopyOperation
|
||||
| ReplaceOperation
|
||||
| RunScriptOperation
|
||||
| BurnOperation;
|
||||
percentage: number;
|
||||
}
|
||||
|
||||
interface Operation {
|
||||
command: string;
|
||||
}
|
||||
|
||||
interface CopyOperation extends Operation {
|
||||
command: 'copy';
|
||||
from: { path: string };
|
||||
to: { path: string };
|
||||
}
|
||||
|
||||
interface ReplaceOperation extends Operation {
|
||||
command: 'replace';
|
||||
copy: string;
|
||||
replace: string;
|
||||
file: {
|
||||
path: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface RunScriptOperation extends Operation {
|
||||
command: 'run-script';
|
||||
script: string;
|
||||
arguments?: string[];
|
||||
}
|
||||
|
||||
interface BurnOperation extends Operation {
|
||||
command: 'burn';
|
||||
image?: string;
|
||||
}
|
||||
|
||||
interface BurnProgress {
|
||||
type: 'write' | 'check';
|
||||
percentage: number;
|
||||
transferred: number;
|
||||
length: number;
|
||||
remaining: number;
|
||||
eta: number;
|
||||
runtime: number;
|
||||
delta: number;
|
||||
speed: number;
|
||||
}
|
||||
|
||||
interface InitializeEmitter {
|
||||
on(event: 'stdout' | 'stderr', callback: (msg: string) => void): void;
|
||||
on(event: 'state', callback: (state: OperationState) => void): void;
|
||||
on(event: 'burn', callback: (state: BurnProgress) => void): void;
|
||||
on(event: 'end', callback: () => void): void;
|
||||
on(event: 'error', callback: (error: Error) => void): void;
|
||||
}
|
||||
|
||||
export function configure(
|
||||
image: string,
|
||||
manifest: BalenaSdk.DeviceTypeJson.DeviceType.DeviceType,
|
||||
config: object,
|
||||
options?: object,
|
||||
): Bluebird<InitializeEmitter>;
|
||||
|
||||
export function initialize(
|
||||
image: string,
|
||||
manifest: BalenaSdk.DeviceTypeJson.DeviceType.DeviceType,
|
||||
config: object,
|
||||
): Bluebird<InitializeEmitter>;
|
||||
|
||||
export function getImageOsVersion(
|
||||
image: string,
|
||||
manifest: BalenaSdk.DeviceTypeJson.DeviceType.DeviceType,
|
||||
): Bluebird<string | null>;
|
||||
|
||||
export function getImageManifest(
|
||||
image: string,
|
||||
): Bluebird<BalenaSdk.DeviceTypeJson.DeviceType.DeviceType | null>;
|
||||
}
|
Reference in New Issue
Block a user