New GUI/IDE build script support (#7832)

This PR adds support for the new Vue-based GUI (aka `gui2`).

The user-facing changes are primarily:
* support for `./run gui2` and `./run ide2` commands (that build just the new GUI and the whole IDE package with new GUI embedded — respectively);
* the top-level `test` and `lint` commands will now invoke the relevant commands on the new GUI

---------

Co-authored-by: Paweł Grabarz <frizi09@gmail.com>
This commit is contained in:
Michał Wawrzyniec Urbańczyk 2023-10-03 20:07:20 +02:00 committed by GitHub
parent 8d8c0b62d6
commit 2d39e644b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 1121 additions and 229 deletions

View File

@ -24,7 +24,7 @@ jobs:
conda-channels: anaconda, conda-forge
- if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent')
name: Installing wasm-pack
uses: jetli/wasm-pack-action@v0.4.0
uses: jetli/wasm-pack-action@v0.3.0
with:
version: v0.10.2
- name: Expose Artifact API and context information.
@ -225,7 +225,7 @@ jobs:
run: ./run git-clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: ./run --upload-artifacts ${{ runner.os == 'Linux' }} wasm build
- run: ./run wasm build --wasm-upload-artifact ${{ runner.os == 'Linux' }}
env:
ENSO_AG_GRID_LICENSE_KEY: ${{ secrets.ENSO_AG_GRID_LICENSE_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@ -282,7 +282,7 @@ jobs:
run: ./run git-clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: ./run --upload-artifacts ${{ runner.os == 'Linux' }} wasm build
- run: ./run wasm build --wasm-upload-artifact ${{ runner.os == 'Linux' }}
env:
ENSO_AG_GRID_LICENSE_KEY: ${{ secrets.ENSO_AG_GRID_LICENSE_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@ -341,7 +341,7 @@ jobs:
run: ./run git-clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: ./run --upload-artifacts ${{ runner.os == 'Linux' }} wasm build
- run: ./run wasm build --wasm-upload-artifact ${{ runner.os == 'Linux' }}
env:
ENSO_AG_GRID_LICENSE_KEY: ${{ secrets.ENSO_AG_GRID_LICENSE_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@ -483,8 +483,423 @@ jobs:
run: ./run git-clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
enso-build-ci-gen-job-package-ide-linux:
name: Package IDE (linux)
enso-build-ci-gen-job-new-gui-build-linux:
name: New (Vue) GUI build (linux)
runs-on:
- self-hosted
- Linux
- engine
steps:
- if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent')
name: Setup conda (GH runners only)
uses: s-weigand/setup-conda@v1.0.6
with:
update-conda: false
conda-channels: anaconda, conda-forge
- if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent')
name: Installing wasm-pack
uses: jetli/wasm-pack-action@v0.3.0
with:
version: v0.10.2
- name: Expose Artifact API and context information.
uses: actions/github-script@v6
with:
script: "\n core.exportVariable(\"ACTIONS_RUNTIME_TOKEN\", process.env[\"ACTIONS_RUNTIME_TOKEN\"])\n core.exportVariable(\"ACTIONS_RUNTIME_URL\", process.env[\"ACTIONS_RUNTIME_URL\"])\n core.exportVariable(\"GITHUB_RETENTION_DAYS\", process.env[\"GITHUB_RETENTION_DAYS\"])\n console.log(context)\n "
- if: runner.os == 'Windows'
name: Workaround for https://github.com/actions/checkout/issues/590 (Windows)
run: '"c:\Program Files\Git\bin\bash.exe" -c "git checkout -f $(git -c user.name=x -c user.email=x@x commit-tree $(git hash-object -t tree /dev/null) < /dev/null) || :"'
shell: cmd
- if: runner.os != 'Windows'
name: Workaround for https://github.com/actions/checkout/issues/590 (non-Windows)
run: "git checkout -f $(git -c user.name=x -c user.email=x@x commit-tree $(git hash-object -t tree /dev/null) < /dev/null) || :"
shell: bash
- name: Checking out the repository
uses: actions/checkout@v2
with:
clean: false
submodules: recursive
- name: Build Script Setup
run: ./run --help
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- if: "contains(github.event.pull_request.labels.*.name, 'CI: Clean build required')"
name: Clean before
run: ./run git-clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: ./run gui2 build
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- if: failure() && runner.os == 'Windows'
name: List files if failed (Windows)
run: Get-ChildItem -Force -Recurse
- if: failure() && runner.os != 'Windows'
name: List files if failed (non-Windows)
run: ls -lAR
- if: "always() && always() && contains(github.event.pull_request.labels.*.name, 'CI: Clean build required')"
name: Clean after
run: ./run git-clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
enso-build-ci-gen-job-new-gui-build-macos:
name: New (Vue) GUI build (macos)
runs-on:
- macos-latest
steps:
- if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent')
name: Setup conda (GH runners only)
uses: s-weigand/setup-conda@v1.0.6
with:
update-conda: false
conda-channels: anaconda, conda-forge
- if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent')
name: Installing wasm-pack
uses: jetli/wasm-pack-action@v0.3.0
with:
version: v0.10.2
- name: Expose Artifact API and context information.
uses: actions/github-script@v6
with:
script: "\n core.exportVariable(\"ACTIONS_RUNTIME_TOKEN\", process.env[\"ACTIONS_RUNTIME_TOKEN\"])\n core.exportVariable(\"ACTIONS_RUNTIME_URL\", process.env[\"ACTIONS_RUNTIME_URL\"])\n core.exportVariable(\"GITHUB_RETENTION_DAYS\", process.env[\"GITHUB_RETENTION_DAYS\"])\n console.log(context)\n "
- if: runner.os == 'Windows'
name: Workaround for https://github.com/actions/checkout/issues/590 (Windows)
run: '"c:\Program Files\Git\bin\bash.exe" -c "git checkout -f $(git -c user.name=x -c user.email=x@x commit-tree $(git hash-object -t tree /dev/null) < /dev/null) || :"'
shell: cmd
- if: runner.os != 'Windows'
name: Workaround for https://github.com/actions/checkout/issues/590 (non-Windows)
run: "git checkout -f $(git -c user.name=x -c user.email=x@x commit-tree $(git hash-object -t tree /dev/null) < /dev/null) || :"
shell: bash
- name: Checking out the repository
uses: actions/checkout@v2
with:
clean: false
submodules: recursive
- name: Build Script Setup
run: ./run --help
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- if: "contains(github.event.pull_request.labels.*.name, 'CI: Clean build required')"
name: Clean before
run: ./run git-clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: ./run gui2 build
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- if: failure() && runner.os == 'Windows'
name: List files if failed (Windows)
run: Get-ChildItem -Force -Recurse
- if: failure() && runner.os != 'Windows'
name: List files if failed (non-Windows)
run: ls -lAR
- if: "always() && always() && contains(github.event.pull_request.labels.*.name, 'CI: Clean build required')"
name: Clean after
run: ./run git-clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
enso-build-ci-gen-job-new-gui-build-windows:
name: New (Vue) GUI build (windows)
runs-on:
- self-hosted
- Windows
- engine
steps:
- if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent')
name: Setup conda (GH runners only)
uses: s-weigand/setup-conda@v1.0.6
with:
update-conda: false
conda-channels: anaconda, conda-forge
- if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent')
name: Installing wasm-pack
uses: jetli/wasm-pack-action@v0.3.0
with:
version: v0.10.2
- name: Expose Artifact API and context information.
uses: actions/github-script@v6
with:
script: "\n core.exportVariable(\"ACTIONS_RUNTIME_TOKEN\", process.env[\"ACTIONS_RUNTIME_TOKEN\"])\n core.exportVariable(\"ACTIONS_RUNTIME_URL\", process.env[\"ACTIONS_RUNTIME_URL\"])\n core.exportVariable(\"GITHUB_RETENTION_DAYS\", process.env[\"GITHUB_RETENTION_DAYS\"])\n console.log(context)\n "
- if: runner.os == 'Windows'
name: Workaround for https://github.com/actions/checkout/issues/590 (Windows)
run: '"c:\Program Files\Git\bin\bash.exe" -c "git checkout -f $(git -c user.name=x -c user.email=x@x commit-tree $(git hash-object -t tree /dev/null) < /dev/null) || :"'
shell: cmd
- if: runner.os != 'Windows'
name: Workaround for https://github.com/actions/checkout/issues/590 (non-Windows)
run: "git checkout -f $(git -c user.name=x -c user.email=x@x commit-tree $(git hash-object -t tree /dev/null) < /dev/null) || :"
shell: bash
- name: Checking out the repository
uses: actions/checkout@v2
with:
clean: false
submodules: recursive
- name: Build Script Setup
run: ./run --help
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- if: "contains(github.event.pull_request.labels.*.name, 'CI: Clean build required')"
name: Clean before
run: ./run git-clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: ./run gui2 build
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- if: failure() && runner.os == 'Windows'
name: List files if failed (Windows)
run: Get-ChildItem -Force -Recurse
- if: failure() && runner.os != 'Windows'
name: List files if failed (non-Windows)
run: ls -lAR
- if: "always() && always() && contains(github.event.pull_request.labels.*.name, 'CI: Clean build required')"
name: Clean after
run: ./run git-clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
enso-build-ci-gen-job-new-gui-test-linux:
name: New (Vue) GUI tests (linux)
runs-on:
- self-hosted
- Linux
- engine
steps:
- if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent')
name: Setup conda (GH runners only)
uses: s-weigand/setup-conda@v1.0.6
with:
update-conda: false
conda-channels: anaconda, conda-forge
- if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent')
name: Installing wasm-pack
uses: jetli/wasm-pack-action@v0.3.0
with:
version: v0.10.2
- name: Expose Artifact API and context information.
uses: actions/github-script@v6
with:
script: "\n core.exportVariable(\"ACTIONS_RUNTIME_TOKEN\", process.env[\"ACTIONS_RUNTIME_TOKEN\"])\n core.exportVariable(\"ACTIONS_RUNTIME_URL\", process.env[\"ACTIONS_RUNTIME_URL\"])\n core.exportVariable(\"GITHUB_RETENTION_DAYS\", process.env[\"GITHUB_RETENTION_DAYS\"])\n console.log(context)\n "
- if: runner.os == 'Windows'
name: Workaround for https://github.com/actions/checkout/issues/590 (Windows)
run: '"c:\Program Files\Git\bin\bash.exe" -c "git checkout -f $(git -c user.name=x -c user.email=x@x commit-tree $(git hash-object -t tree /dev/null) < /dev/null) || :"'
shell: cmd
- if: runner.os != 'Windows'
name: Workaround for https://github.com/actions/checkout/issues/590 (non-Windows)
run: "git checkout -f $(git -c user.name=x -c user.email=x@x commit-tree $(git hash-object -t tree /dev/null) < /dev/null) || :"
shell: bash
- name: Checking out the repository
uses: actions/checkout@v2
with:
clean: false
submodules: recursive
- name: Build Script Setup
run: ./run --help
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- if: "contains(github.event.pull_request.labels.*.name, 'CI: Clean build required')"
name: Clean before
run: ./run git-clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: ./run gui2 test
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- if: failure() && runner.os == 'Windows'
name: List files if failed (Windows)
run: Get-ChildItem -Force -Recurse
- if: failure() && runner.os != 'Windows'
name: List files if failed (non-Windows)
run: ls -lAR
- if: "always() && always() && contains(github.event.pull_request.labels.*.name, 'CI: Clean build required')"
name: Clean after
run: ./run git-clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
enso-build-ci-gen-job-package-new-ide-linux:
name: Package New IDE (linux)
needs:
- enso-build-ci-gen-job-build-backend-linux
runs-on:
- self-hosted
- Linux
- engine
steps:
- if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent')
name: Setup conda (GH runners only)
uses: s-weigand/setup-conda@v1.0.6
with:
update-conda: false
conda-channels: anaconda, conda-forge
- if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent')
name: Installing wasm-pack
uses: jetli/wasm-pack-action@v0.3.0
with:
version: v0.10.2
- name: Expose Artifact API and context information.
uses: actions/github-script@v6
with:
script: "\n core.exportVariable(\"ACTIONS_RUNTIME_TOKEN\", process.env[\"ACTIONS_RUNTIME_TOKEN\"])\n core.exportVariable(\"ACTIONS_RUNTIME_URL\", process.env[\"ACTIONS_RUNTIME_URL\"])\n core.exportVariable(\"GITHUB_RETENTION_DAYS\", process.env[\"GITHUB_RETENTION_DAYS\"])\n console.log(context)\n "
- if: runner.os == 'Windows'
name: Workaround for https://github.com/actions/checkout/issues/590 (Windows)
run: '"c:\Program Files\Git\bin\bash.exe" -c "git checkout -f $(git -c user.name=x -c user.email=x@x commit-tree $(git hash-object -t tree /dev/null) < /dev/null) || :"'
shell: cmd
- if: runner.os != 'Windows'
name: Workaround for https://github.com/actions/checkout/issues/590 (non-Windows)
run: "git checkout -f $(git -c user.name=x -c user.email=x@x commit-tree $(git hash-object -t tree /dev/null) < /dev/null) || :"
shell: bash
- name: Checking out the repository
uses: actions/checkout@v2
with:
clean: false
submodules: recursive
- name: Build Script Setup
run: ./run --help
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- if: "contains(github.event.pull_request.labels.*.name, 'CI: Clean build required')"
name: Clean before
run: ./run git-clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: ./run ide2 build --backend-source current-ci-run --gui2-upload-artifact false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- if: failure() && runner.os == 'Windows'
name: List files if failed (Windows)
run: Get-ChildItem -Force -Recurse
- if: failure() && runner.os != 'Windows'
name: List files if failed (non-Windows)
run: ls -lAR
- if: "always() && always() && contains(github.event.pull_request.labels.*.name, 'CI: Clean build required')"
name: Clean after
run: ./run git-clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
enso-build-ci-gen-job-package-new-ide-macos:
name: Package New IDE (macos)
needs:
- enso-build-ci-gen-job-build-backend-macos
runs-on:
- macos-latest
steps:
- if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent')
name: Setup conda (GH runners only)
uses: s-weigand/setup-conda@v1.0.6
with:
update-conda: false
conda-channels: anaconda, conda-forge
- if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent')
name: Installing wasm-pack
uses: jetli/wasm-pack-action@v0.3.0
with:
version: v0.10.2
- name: Expose Artifact API and context information.
uses: actions/github-script@v6
with:
script: "\n core.exportVariable(\"ACTIONS_RUNTIME_TOKEN\", process.env[\"ACTIONS_RUNTIME_TOKEN\"])\n core.exportVariable(\"ACTIONS_RUNTIME_URL\", process.env[\"ACTIONS_RUNTIME_URL\"])\n core.exportVariable(\"GITHUB_RETENTION_DAYS\", process.env[\"GITHUB_RETENTION_DAYS\"])\n console.log(context)\n "
- if: runner.os == 'Windows'
name: Workaround for https://github.com/actions/checkout/issues/590 (Windows)
run: '"c:\Program Files\Git\bin\bash.exe" -c "git checkout -f $(git -c user.name=x -c user.email=x@x commit-tree $(git hash-object -t tree /dev/null) < /dev/null) || :"'
shell: cmd
- if: runner.os != 'Windows'
name: Workaround for https://github.com/actions/checkout/issues/590 (non-Windows)
run: "git checkout -f $(git -c user.name=x -c user.email=x@x commit-tree $(git hash-object -t tree /dev/null) < /dev/null) || :"
shell: bash
- name: Checking out the repository
uses: actions/checkout@v2
with:
clean: false
submodules: recursive
- name: Build Script Setup
run: ./run --help
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- if: "contains(github.event.pull_request.labels.*.name, 'CI: Clean build required')"
name: Clean before
run: ./run git-clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: ./run ide2 build --backend-source current-ci-run --gui2-upload-artifact false
env:
APPLEID: ${{ secrets.APPLE_NOTARIZATION_USERNAME }}
APPLEIDPASS: ${{ secrets.APPLE_NOTARIZATION_PASSWORD }}
CSC_IDENTITY_AUTO_DISCOVERY: "true"
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CODE_SIGNING_CERT_PASSWORD }}
CSC_LINK: ${{ secrets.APPLE_CODE_SIGNING_CERT }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- if: failure() && runner.os == 'Windows'
name: List files if failed (Windows)
run: Get-ChildItem -Force -Recurse
- if: failure() && runner.os != 'Windows'
name: List files if failed (non-Windows)
run: ls -lAR
- if: "always() && always() && contains(github.event.pull_request.labels.*.name, 'CI: Clean build required')"
name: Clean after
run: ./run git-clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
enso-build-ci-gen-job-package-new-ide-windows:
name: Package New IDE (windows)
needs:
- enso-build-ci-gen-job-build-backend-windows
runs-on:
- self-hosted
- Windows
- engine
steps:
- if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent')
name: Setup conda (GH runners only)
uses: s-weigand/setup-conda@v1.0.6
with:
update-conda: false
conda-channels: anaconda, conda-forge
- if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent')
name: Installing wasm-pack
uses: jetli/wasm-pack-action@v0.3.0
with:
version: v0.10.2
- name: Expose Artifact API and context information.
uses: actions/github-script@v6
with:
script: "\n core.exportVariable(\"ACTIONS_RUNTIME_TOKEN\", process.env[\"ACTIONS_RUNTIME_TOKEN\"])\n core.exportVariable(\"ACTIONS_RUNTIME_URL\", process.env[\"ACTIONS_RUNTIME_URL\"])\n core.exportVariable(\"GITHUB_RETENTION_DAYS\", process.env[\"GITHUB_RETENTION_DAYS\"])\n console.log(context)\n "
- if: runner.os == 'Windows'
name: Workaround for https://github.com/actions/checkout/issues/590 (Windows)
run: '"c:\Program Files\Git\bin\bash.exe" -c "git checkout -f $(git -c user.name=x -c user.email=x@x commit-tree $(git hash-object -t tree /dev/null) < /dev/null) || :"'
shell: cmd
- if: runner.os != 'Windows'
name: Workaround for https://github.com/actions/checkout/issues/590 (non-Windows)
run: "git checkout -f $(git -c user.name=x -c user.email=x@x commit-tree $(git hash-object -t tree /dev/null) < /dev/null) || :"
shell: bash
- name: Checking out the repository
uses: actions/checkout@v2
with:
clean: false
submodules: recursive
- name: Build Script Setup
run: ./run --help
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- if: "contains(github.event.pull_request.labels.*.name, 'CI: Clean build required')"
name: Clean before
run: ./run git-clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: ./run ide2 build --backend-source current-ci-run --gui2-upload-artifact false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
WIN_CSC_KEY_PASSWORD: ${{ secrets.MICROSOFT_CODE_SIGNING_CERT_PASSWORD }}
WIN_CSC_LINK: ${{ secrets.MICROSOFT_CODE_SIGNING_CERT }}
- if: failure() && runner.os == 'Windows'
name: List files if failed (Windows)
run: Get-ChildItem -Force -Recurse
- if: failure() && runner.os != 'Windows'
name: List files if failed (non-Windows)
run: ls -lAR
- if: "always() && always() && contains(github.event.pull_request.labels.*.name, 'CI: Clean build required')"
name: Clean after
run: ./run git-clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
enso-build-ci-gen-job-package-old-ide-linux:
name: Package Old IDE (linux)
needs:
- enso-build-ci-gen-job-build-backend-linux
- enso-build-ci-gen-job-build-wasm-linux
@ -544,8 +959,8 @@ jobs:
run: ./run git-clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
enso-build-ci-gen-job-package-ide-macos:
name: Package IDE (macos)
enso-build-ci-gen-job-package-old-ide-macos:
name: Package Old IDE (macos)
needs:
- enso-build-ci-gen-job-build-backend-macos
- enso-build-ci-gen-job-build-wasm-linux
@ -608,8 +1023,8 @@ jobs:
run: ./run git-clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
enso-build-ci-gen-job-package-ide-windows:
name: Package IDE (windows)
enso-build-ci-gen-job-package-old-ide-windows:
name: Package Old IDE (windows)
needs:
- enso-build-ci-gen-job-build-backend-windows
- enso-build-ci-gen-job-build-wasm-linux

View File

@ -106,7 +106,7 @@ jobs:
run: ./run git-clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: ./run --upload-artifacts ${{ runner.os == 'Linux' }} wasm build
- run: ./run wasm build --wasm-upload-artifact ${{ runner.os == 'Linux' }}
env:
ENSO_AG_GRID_LICENSE_KEY: ${{ secrets.ENSO_AG_GRID_LICENSE_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

7
.gitignore vendored
View File

@ -91,14 +91,17 @@ bench-report*.xml
## Binaries ##
##############
/built-distribution/
/enso
/project-manager
*.exe
/enso.exp
/enso.lib
*.dll
*.exe
*.pdb
*.so
*.jar
/built-distribution/
#########

View File

@ -40,5 +40,9 @@ ci-build/
enso/
# Popular IDEs
.idea
.bsp
.idea
.vscode
# Stray files generated during build
svm_*.md

View File

@ -1,10 +1,15 @@
{
"rust-analyzer.linkedProjects": ["./app/gui2/rust-ffi/Cargo.toml"],
"rust-analyzer.linkedProjects": [
"./app/gui2/rust-ffi/Cargo.toml"
],
"vue.complete.casing.status": false,
"vue.complete.casing.props": "camel",
"vue.complete.casing.tags": "pascal",
"auto-snippets.snippets": [
{ "language": "vue", "snippet": "Vue single-file component" }
{
"language": "vue",
"snippet": "Vue single-file component"
}
],
"typescript.tsdk": "node_modules/typescript/lib",
"eslint.experimental.useFlatConfig": true,

View File

@ -9,7 +9,7 @@
},
"scripts": {
"dev": "vite",
"build": "run-p typecheck build-only",
"build": "npm --workspace enso-authentication run compile && run-p typecheck build-only",
"preview": "vite preview",
"test:unit": "vitest",
"test:e2e": "playwright test",

View File

@ -97,12 +97,12 @@ export class DistributedModule {
}
insertNewNode(offset: number, content: string, meta: NodeMetadata): ExprId {
const range = [offset, offset + content.length]
const range = [offset, offset + content.length] as const
const newId = random.uuidv4() as ExprId
this.transact(() => {
this.doc.contents.insert(offset, content + '\n')
const start = Y.createRelativePositionFromTypeIndex(this.doc.contents, range[0]!)
const end = Y.createRelativePositionFromTypeIndex(this.doc.contents, range[1]!)
const start = Y.createRelativePositionFromTypeIndex(this.doc.contents, range[0], -1)
const end = Y.createRelativePositionFromTypeIndex(this.doc.contents, range[1])
this.doc.idMap.set(newId, encodeRange([start, end]))
this.doc.metadata.set(newId, meta)
})
@ -281,7 +281,7 @@ export class IdMap {
// For all remaining expressions, we need to write them into the map.
if (!this.accessed.has(expr)) return
const range = IdMap.rangeForKey(key)
const start = Y.createRelativePositionFromTypeIndex(this.contents, range[0])
const start = Y.createRelativePositionFromTypeIndex(this.contents, range[0], -1)
const end = Y.createRelativePositionFromTypeIndex(this.contents, range[1])
const encoded = encodeRange([start, end])
this.yMap.set(expr, encoded)

View File

@ -5,6 +5,7 @@ const INITIAL_URL_KEY = `Enso-initial-url`
import './assets/main.css'
import { basicSetup } from 'codemirror'
import * as dashboard from 'enso-authentication'
import { isMac } from 'lib0/environment'
import { decodeQueryParams } from 'lib0/url'
import { createPinia } from 'pinia'
@ -46,8 +47,6 @@ function stopApp() {
const appRunner = { runApp, stopApp }
const dashboard = await import('enso-authentication')
/** The entrypoint into the IDE. */
function main() {
/** Note: Signing out always redirects to `/`. It is impossible to make this work,

View File

@ -154,7 +154,7 @@ export const useGraphStore = defineStore('graph', () => {
rootSpan: stmt.expression,
position: meta == null ? Vec2.Zero() : new Vec2(meta.x, -meta.y),
docRange: [
Y.createRelativePositionFromTypeIndex(text, stmt.exprOffset),
Y.createRelativePositionFromTypeIndex(text, stmt.exprOffset, -1),
Y.createRelativePositionFromTypeIndex(text, stmt.exprOffset + stmt.expression.length),
],
}

View File

@ -349,16 +349,18 @@ class ModulePersistence extends ObservableV2<{ removed: () => void }> {
newContent += synced.code
}
newContent += META_TAG + '\n'
const metaStartLine = (newContent.match(/\n/g) ?? []).length
let metaContent = META_TAG + '\n'
if (idMapKeys != null || (contentDelta && contentDelta.length > 0)) {
if (
idMapKeys != null ||
synced.idMapJson == null ||
(contentDelta && contentDelta.length > 0)
) {
const idMapJson = json.stringify(idMapToArray(this.doc.idMap))
allEdits.push(...applyDiffAsTextEdits(metaStartLine, synced.idMapJson ?? '', idMapJson))
newContent += idMapJson + '\n'
metaContent += idMapJson + '\n'
} else {
newContent += synced.idMapJson + '\n'
metaContent += (synced.idMapJson ?? '[]') + '\n'
}
const nodeMetadata = this.syncedMeta.ide.node
@ -385,14 +387,15 @@ class ModulePersistence extends ObservableV2<{ removed: () => void }> {
}
const metadataJson = json.stringify(this.syncedMeta)
allEdits.push(
...applyDiffAsTextEdits(metaStartLine + 1, synced.metadataJson ?? '', metadataJson),
)
newContent += metadataJson
metaContent += metadataJson
} else {
newContent += synced.metadataJson
metaContent += synced.metadataJson ?? '{}'
}
const oldMetaContent = this.syncedContent.slice(synced.code.length)
allEdits.push(...applyDiffAsTextEdits(metaStartLine, oldMetaContent, metaContent))
newContent += metaContent
const newVersion = computeTextChecksum(newContent)
if (DEBUG_LOG_SYNC) {

View File

@ -99,7 +99,7 @@ export function createElectronBuilderConfig(passedArgs: Arguments): electronBuil
extraMetadata: {
version: BUILD_INFO.version,
},
copyright: 'Copyright © 2022 ${author}.',
copyright: `Copyright © ${new Date().getFullYear()} ${common.COMPANY_NAME}`,
artifactName: 'enso-${os}-${version}.${ext}',
/** Definitions of URL {@link electronBuilder.Protocol} schemes used by the IDE.
*

View File

@ -100,6 +100,7 @@ export class Server {
logger.error(`Error creating server:`, err.http)
reject(err)
}
// Prepare the YDoc server access point for the new Vue-based GUI.
if (httpServer) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,
// @typescript-eslint/no-unsafe-call

View File

@ -18,6 +18,9 @@ export const DEEP_LINK_SCHEME = 'enso'
/** Name of the product. */
export const PRODUCT_NAME = 'Enso'
/** Company name, used as the copyright holder. */
export const COMPANY_NAME = 'New Byte Order sp. z o.o.'
/** COOP, COEP, and CORP headers: https://web.dev/coop-coep/
*
* These are required to increase the resolution of `performance.now()` timers,

View File

@ -9,6 +9,7 @@
"./tailwind.css": "./tailwind.css"
},
"scripts": {
"compile": "tsc",
"typecheck": "tsc --noEmit"
},
"dependencies": {

View File

@ -185,11 +185,7 @@ declare module 'create-servers' {
option: CreateServersOptions,
// The types come from a third-party API and cannot be changed.
// eslint-disable-next-line no-restricted-syntax
handler: (
// eslint-disable-next-line no-restricted-syntax
err: HttpError | undefined,
servers: CreatedServers
) => void
handler: (err: HttpError | undefined, servers: CreatedServers) => void
): unknown
}

View File

@ -6,7 +6,7 @@ required-versions:
# NB. The Rust version is pinned in rust-toolchain.toml.
# NB. The Node version is pinned in .node-version.
cargo-watch: ^8.1.1
wasm-pack: ^0.10.2
wasm-pack: ^0.12.1
# TODO [mwu]: Script can install `flatc` later on (if `conda` is present), so this is not required. However it should
# be required, if `conda` is missing.
# flatc: =1.12.0

View File

@ -15,6 +15,8 @@
shader-tools.yml:
app/:
gui/:
gui2/: # The new, Vue-based GUI.
dist/:
ide-desktop/:
lib/:
client/:
@ -57,6 +59,9 @@
index.js:
style.css:
gui2/:
assets/:
# Final WASM artifacts in `dist` directory.
wasm/:
dynamic-assets/: # Assets used by the WASM application.

View File

@ -445,6 +445,7 @@ pub fn gui() -> Result<Workflow> {
workflow.add(PRIMARY_OS, job::Lint);
workflow.add(PRIMARY_OS, job::WasmTest);
workflow.add(PRIMARY_OS, job::NativeTest);
workflow.add(PRIMARY_OS, job::NewGuiTest);
// FIXME: Integration tests are currently always failing.
// The should be reinstated when fixed.
@ -461,10 +462,14 @@ pub fn gui() -> Result<Workflow> {
let _wasm_job = workflow.add(os, job::BuildWasm);
}
let project_manager_job = workflow.add(os, job::BuildBackend);
workflow.add_customized(os, job::PackageIde, |job| {
workflow.add_customized(os, job::PackageOldIde, |job| {
job.needs.insert(wasm_job_linux.clone());
job.needs.insert(project_manager_job);
job.needs.insert(project_manager_job.clone());
});
workflow.add_customized(os, job::PackageNewIde, |job| {
job.needs.insert(project_manager_job.clone());
});
workflow.add(os, job::NewGuiBuild);
}
Ok(workflow)
}

View File

@ -105,6 +105,22 @@ impl JobArchetype for NativeTest {
}
}
#[derive(Clone, Copy, Debug)]
pub struct NewGuiTest;
impl JobArchetype for NewGuiTest {
fn job(&self, os: OS) -> Job {
plain_job(&os, "New (Vue) GUI tests", "gui2 test")
}
}
#[derive(Clone, Copy, Debug)]
pub struct NewGuiBuild;
impl JobArchetype for NewGuiBuild {
fn job(&self, os: OS) -> Job {
plain_job(&os, "New (Vue) GUI build", "gui2 build")
}
}
#[derive(Clone, Copy, Debug)]
pub struct WasmTest;
impl JobArchetype for WasmTest {
@ -132,7 +148,7 @@ impl JobArchetype for BuildWasm {
plain_job_customized(
&os,
"Build GUI (WASM)",
" --upload-artifacts ${{ runner.os == 'Linux' }} wasm build",
"wasm build --wasm-upload-artifact ${{ runner.os == 'Linux' }}",
|step| vec![step.with_secret_exposed(crate::env::ENSO_AG_GRID_LICENSE_KEY)],
)
}
@ -222,18 +238,31 @@ pub fn expose_os_specific_signing_secret(os: OS, step: Step) -> Step {
}
#[derive(Clone, Copy, Debug)]
pub struct PackageIde;
impl JobArchetype for PackageIde {
pub struct PackageOldIde;
impl JobArchetype for PackageOldIde {
fn job(&self, os: OS) -> Job {
plain_job_customized(
&os,
"Package IDE",
"Package Old IDE",
"ide build --wasm-source current-ci-run --backend-source current-ci-run",
|step| vec![expose_os_specific_signing_secret(os, step)],
)
}
}
#[derive(Clone, Copy, Debug)]
pub struct PackageNewIde;
impl JobArchetype for PackageNewIde {
fn job(&self, os: OS) -> Job {
plain_job_customized(
&os,
"Package New IDE",
"ide2 build --backend-source current-ci-run --gui2-upload-artifact false",
|step| vec![expose_os_specific_signing_secret(os, step)],
)
}
}
#[derive(Clone, Copy, Debug)]
pub struct CiCheckBackend;
impl JobArchetype for CiCheckBackend {

View File

@ -4,6 +4,7 @@ use crate::ide::web::env::CSC_KEY_PASSWORD;
use crate::paths::generated;
use crate::project::gui::BuildInfo;
use crate::project::wasm;
use crate::project::IsArtifact;
use crate::project::ProcessWrapper;
use anyhow::Context;
@ -165,9 +166,7 @@ impl<Output: AsRef<Path>> ContentEnvironment<TempDir, Output> {
build_info: &BuildInfo,
output_path: Output,
) -> Result<Self> {
// wasm build already does this, running `npm install` twice concurrently leads to broken
// builds.
// self.npm()?.install().run_ok().await?;
crate::web::install(&ide.repo_root).await?;
let asset_dir = TempDir::new()?;
let assets_download = download_js_assets(&asset_dir);
let fonts_download = fonts::install_html_fonts(&ide.cache, &ide.octocrab, &asset_dir);
@ -240,11 +239,11 @@ impl FallibleManipulator for ProjectManagerInfo {
#[derive(Clone, Derivative)]
#[derivative(Debug)]
pub struct IdeDesktop {
pub build_sbt: generated::RepoRootBuildSbt,
pub package_dir: generated::RepoRoot,
pub build_sbt: generated::RepoRootBuildSbt,
pub repo_root: generated::RepoRoot,
#[derivative(Debug = "ignore")]
pub octocrab: Octocrab,
pub cache: ide_ci::cache::Cache,
pub octocrab: Octocrab,
pub cache: ide_ci::cache::Cache,
}
impl IdeDesktop {
@ -255,7 +254,7 @@ impl IdeDesktop {
) -> Self {
Self {
build_sbt: repo_root.build_sbt.clone(),
package_dir: repo_root.clone(),
repo_root: repo_root.clone(),
octocrab,
cache,
}
@ -265,13 +264,13 @@ impl IdeDesktop {
let mut command = Npm.cmd()?;
command.arg("--color").arg("always");
command.arg("--yes");
command.current_dir(&self.package_dir);
command.current_dir(&self.repo_root);
command.stdin(Stdio::null()); // nothing in that process subtree should require input
Ok(command)
}
pub fn write_build_info(&self, info: &BuildInfo) -> Result {
let path = self.package_dir.join(&*BUILD_INFO);
let path = self.repo_root.join(&*BUILD_INFO);
path.write_as_json(info)
}
@ -340,7 +339,7 @@ impl IdeDesktop {
err))]
pub async fn dist(
&self,
gui: &crate::project::gui::Artifact,
gui: &impl IsArtifact,
project_manager: &crate::project::backend::Artifact,
output_path: impl AsRef<Path>,
target_os: OS,
@ -354,11 +353,12 @@ impl IdeDesktop {
graalvm.install_if_missing(&self.cache).await?;
}
self.npm()?.install().run_ok().await?;
crate::web::install(&self.repo_root).await?;
let pm_bundle = ProjectManagerInfo::new(project_manager)?;
let client_build = self
.npm()?
.set_env(env::ENSO_BUILD_GUI, gui.as_path())?
.set_env(env::ENSO_BUILD_GUI, gui.as_ref())?
.set_env(env::ENSO_BUILD_IDE, output_path.as_ref())?
.try_applying(&pm_bundle)?
.workspace(Workspaces::Enso)
@ -389,7 +389,7 @@ impl IdeDesktop {
self.npm()?
.try_applying(&icons)?
// .env("DEBUG", "electron-builder")
.set_env(env::ENSO_BUILD_GUI, gui.as_path())?
.set_env(env::ENSO_BUILD_GUI, gui.as_ref())?
.set_env(env::ENSO_BUILD_IDE, output_path.as_ref())?
.set_env(env::ENSO_BUILD_PROJECT_MANAGER, project_manager.as_ref())?
.set_env_opt(env::PYTHON_PATH, python_path.as_ref())?
@ -416,7 +416,7 @@ impl IdeDesktop {
get_project_manager: BoxFuture<'static, Result<crate::project::backend::Artifact>>,
ide_options: Vec<String>,
) -> Result {
let npm_install_job = self.npm()?.install().run_ok();
let npm_install_job = crate::web::install(&self.repo_root);
// TODO: This could be possibly optimized by awaiting WASM a bit later, and passing its
// future to the ContentEnvironment. However, the code would get a little tricky.
// Should be reconsidered in the future, based on actual timings.

View File

@ -16,6 +16,7 @@
#![feature(once_cell)]
#![feature(duration_constants)]
#![feature(slice_take)]
#![feature(future_join)]
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
@ -66,6 +67,7 @@ pub mod repo;
pub mod rust;
pub mod source;
pub mod version;
pub mod web;
/// Get version of Enso from the `build.sbt` file contents.
pub fn get_enso_version(build_sbt_contents: &str) -> Result<Version> {

View File

@ -27,7 +27,9 @@ use octocrab::models::repos::Asset;
pub mod backend;
pub mod engine;
pub mod gui;
pub mod gui2;
pub mod ide;
pub mod ide2;
pub mod project_manager;
pub mod runtime;
pub mod wasm;
@ -48,7 +50,7 @@ pub fn path_to_extract() -> Option<PathBuf> {
/// A built target, contained under a single directory.
///
/// The `AsRef<Path>` trait must return that directory path.
pub trait IsArtifact: Clone + AsRef<Path> + Sized + Send + Sync + 'static {}
pub trait IsArtifact: Clone + AsRef<Path> + Debug + Sized + Send + Sync + 'static {}
/// Plain artifact is just a folder with... things.
#[derive(Clone, Derivative)]
@ -89,9 +91,6 @@ pub struct Context {
/// Stores things like downloaded release assets to save time.
pub cache: Cache,
/// Whether built artifacts should be uploaded as part of CI run. Works only in CI environment.
pub upload_artifacts: bool,
/// Directory being an `enso` repository's working copy.
///
/// The directory is not required to be a git repository. It is allowed to use source tarballs
@ -126,6 +125,7 @@ pub trait IsTarget: Clone + Debug + Sized + Send + Sync + 'static {
/// Create a full artifact description from an on-disk representation.
fn adapt_artifact(self, path: impl AsRef<Path>) -> BoxFuture<'static, Result<Self::Artifact>>;
/// Produce the target artifacts, according to the job description.
fn get(
&self,
context: Context,
@ -133,10 +133,10 @@ pub trait IsTarget: Clone + Debug + Sized + Send + Sync + 'static {
) -> BoxFuture<'static, Result<Self::Artifact>> {
let GetTargetJob { destination, inner } = job;
match inner {
Source::BuildLocally(inputs) =>
self.build(context, WithDestination { inner: inputs, destination }),
Source::BuildLocally(local_build) =>
self.build(context, WithDestination::new(local_build, destination)),
Source::External(external) =>
self.get_external(context, WithDestination { inner: external, destination }),
self.get_external(context, WithDestination::new(external, destination)),
}
}
@ -178,8 +178,8 @@ pub trait IsTarget: Clone + Debug + Sized + Send + Sync + 'static {
job: BuildTargetJob<Self>,
) -> BoxFuture<'static, Result<Self::Artifact>> {
let span = debug_span!("Building.", ?self, ?context, ?job).entered();
let upload_artifacts = context.upload_artifacts;
let artifact_fut = self.build_internal(context, job);
let upload_artifacts = job.should_upload_artifact;
let artifact_fut = self.build_internal(context, job.map(|job| job.input));
let this = self.clone();
async move {
let artifact = artifact_fut.await.context(format!("Failed to build {this:?}."))?;
@ -208,7 +208,7 @@ pub trait IsTarget: Clone + Debug + Sized + Send + Sync + 'static {
fn build_internal(
&self,
context: Context,
job: BuildTargetJob<Self>,
job: WithDestination<Self::BuildInput>,
) -> BoxFuture<'static, Result<Self::Artifact>>;
/// Upload artifact to the current GitHub Actions run.
@ -226,7 +226,7 @@ pub trait IsTarget: Clone + Debug + Sized + Send + Sync + 'static {
ci_run: CiRunSource,
output_path: impl AsRef<Path> + Send + Sync + 'static,
) -> BoxFuture<'static, Result<Self::Artifact>> {
let Context { octocrab, cache, upload_artifacts: _, repo_root: _ } = context;
let Context { octocrab, cache, repo_root: _ } = context;
let CiRunSource { run_id, artifact_name, repository } = ci_run;
let repository = repository.handle(&octocrab);
let span = info_span!("Downloading CI Artifact.", %artifact_name, %repository, target = output_path.as_ref().as_str());
@ -285,7 +285,7 @@ pub trait IsTarget: Clone + Debug + Sized + Send + Sync + 'static {
source: ReleaseSource,
destination: PathBuf,
) -> BoxFuture<'static, Result<Self::Artifact>> {
let Context { octocrab, cache, upload_artifacts: _, repo_root: _ } = context;
let Context { octocrab, cache, repo_root: _ } = context;
let span = info_span!("Downloading built target from a release asset.",
asset_id = source.asset_id.0,
repo = %source.repository);
@ -403,19 +403,17 @@ pub fn perhaps_watch<T: IsWatchable>(
job: GetTargetJob<T>,
watch_input: T::WatchInput,
) -> BoxFuture<'static, Result<PerhapsWatched<T>>> {
match job.inner {
let WithDestination { inner, destination } = job;
match inner {
Source::BuildLocally(local) => target
.watch(context, WatchTargetJob {
watch_input,
build: WithDestination { inner: local, destination: job.destination },
build: WithDestination::new(local, destination),
})
.map_ok(PerhapsWatched::Watched)
.boxed(),
Source::External(external) => target
.get_external(context, WithDestination {
inner: external,
destination: job.destination,
})
.get_external(context, WithDestination { inner: external, destination })
.map_ok(PerhapsWatched::Static)
.boxed(),
}

View File

@ -6,7 +6,6 @@ use crate::paths::TargetTriple;
use crate::project::Context;
use crate::project::IsArtifact;
use crate::project::IsTarget;
use crate::source::BuildTargetJob;
use crate::source::WithDestination;
use crate::version::Versions;
@ -147,7 +146,7 @@ impl IsTarget for Backend {
fn build_internal(
&self,
context: Context,
job: BuildTargetJob<Self>,
job: WithDestination<Self::BuildInput>,
) -> BoxFuture<'static, Result<Self::Artifact>> {
let WithDestination { inner, destination } = job;
let target_os = self.target_os;

View File

@ -9,7 +9,7 @@ use crate::project::IsWatchable;
use crate::project::IsWatcher;
use crate::project::PerhapsWatched;
use crate::project::Wasm;
use crate::source::BuildTargetJob;
use crate::source::BuildSource;
use crate::source::GetTargetJob;
use crate::source::WatchTargetJob;
use crate::source::WithDestination;
@ -120,7 +120,7 @@ impl IsTarget for Gui {
fn build_internal(
&self,
context: Context,
job: BuildTargetJob<Self>,
job: WithDestination<Self::BuildInput>,
) -> BoxFuture<'static, Result<Self::Artifact>> {
let WithDestination { inner, destination } = job;
async move {
@ -134,7 +134,7 @@ impl IsTarget for Gui {
}
let ide = ide_desktop_from_context(&context);
ide.npm()?.install().run_ok().await?;
crate::web::install(&ide.repo_root).await?;
let wasm = Wasm.get(context, inner.wasm);
ide.build_content(wasm, &inner.build_info.await?, &destination).await?;
@ -169,8 +169,12 @@ impl IsWatchable for Gui {
context: Context,
job: WatchTargetJob<Self>,
) -> BoxFuture<'static, Result<Self::Watcher>> {
let WatchTargetJob { watch_input, build: WithDestination { inner, destination } } = job;
let BuildInput { build_info, wasm } = inner;
let WatchTargetJob {
watch_input,
build:
WithDestination { inner: BuildSource { input, should_upload_artifact: _ }, destination },
} = job;
let BuildInput { build_info, wasm } = input;
let perhaps_watched_wasm = perhaps_watch(Wasm, context.clone(), wasm, watch_input.wasm);
let ide = ide_desktop_from_context(&context);
async move {
@ -194,8 +198,12 @@ impl Gui {
context: Context,
job: WatchTargetJob<Self>,
) -> GuiBuildWithWatchedWasm {
let WatchTargetJob { watch_input, build: WithDestination { inner, destination } } = job;
let BuildInput { build_info, wasm } = inner;
let WatchTargetJob {
watch_input,
build:
WithDestination { inner: BuildSource { input, should_upload_artifact: _ }, destination },
} = job;
let BuildInput { build_info, wasm } = input;
let WatchInput { wasm: wasm_watch_input } = watch_input;
let perhaps_watched_wasm = perhaps_watch(Wasm, context, wasm, wasm_watch_input);
GuiBuildWithWatchedWasm { perhaps_watched_wasm, build_info, destination }

View File

@ -0,0 +1,139 @@
//! Build logic for the "new GUI" (gui2) project.
//!
//! The new GUI is Vue.js-based and located under `app/gui2`.
use crate::prelude::*;
use crate::paths::generated::RepoRootAppGui2Dist;
use crate::paths::generated::RepoRootDistGui2Assets;
use crate::project::Context;
use crate::project::IsArtifact;
use crate::project::IsTarget;
use crate::source::WithDestination;
use ide_ci::ok_ready_boxed;
use ide_ci::programs::node::NpmCommand;
use ide_ci::programs::Npm;
// ===============
// === Scripts ===
// ===============
/// The scripts defined in `package.json`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::AsRefStr)]
#[strum(serialize_all = "kebab-case")]
pub enum Scripts {
Dev,
Build,
Preview,
#[strum(serialize = "test:unit")]
TestUnit,
#[strum(serialize = "test:e2e")]
TestE2e,
BuildOnly,
TypeCheck,
Lint,
Format,
BuildRustFfi,
}
pub fn script(repo_root: impl AsRef<Path>, script: Scripts) -> Result<NpmCommand> {
let mut ret = Npm.cmd()?;
ret.current_dir(repo_root).workspace(crate::web::Workspace::EnsoGui2).run(script.as_ref());
Ok(ret)
}
// ================
// === Commands ===
// ================
/// Run steps that should be done along with the "lint"
pub fn lint(repo_root: impl AsRef<Path>) -> BoxFuture<'static, Result> {
let repo_root = repo_root.as_ref().to_owned();
async move {
crate::web::install(&repo_root).await?;
script(&repo_root, Scripts::Lint)?.run_ok().await
}
.boxed()
}
/// Run unit tests.
pub fn unit_tests(repo_root: impl AsRef<Path>) -> BoxFuture<'static, Result> {
let repo_root = repo_root.as_ref().to_owned();
async move {
crate::web::install(&repo_root).await?;
script(&repo_root, Scripts::TestUnit)?.arg("run").run_ok().await
}
.boxed()
}
// ================
// === Artifact ===
// ================
/// The [artifact](IsArtifact) for the new GUI.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Deref)]
pub struct Artifact(pub RepoRootAppGui2Dist);
impl AsRef<Path> for Artifact {
fn as_ref(&self) -> &Path {
self.0.as_path()
}
}
impl IsArtifact for Artifact {}
impl Artifact {
pub fn new(path: impl AsRef<Path>) -> Self {
Artifact(RepoRootAppGui2Dist::new_root(path.as_ref()))
}
}
// ==============
// === Target ===
// ==============
/// The [target](IsTarget) for the new GUI.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Gui2;
impl IsTarget for Gui2 {
type BuildInput = ();
type Artifact = Artifact;
fn artifact_name(&self) -> String {
"gui2".to_owned()
}
fn adapt_artifact(self, path: impl AsRef<Path>) -> BoxFuture<'static, Result<Self::Artifact>> {
ok_ready_boxed(Artifact::new(path))
}
fn build_internal(
&self,
context: Context,
job: WithDestination<Self::BuildInput>,
) -> BoxFuture<'static, Result<Self::Artifact>> {
let WithDestination { inner: _, destination } = job;
async move {
let repo_root = &context.repo_root;
crate::web::install(repo_root).await?;
script(repo_root, Scripts::Build)?.run_ok().await?;
ide_ci::fs::mirror_directory(
&repo_root.app.gui_2.dist,
&destination.join(RepoRootDistGui2Assets::segment_name()),
)
.await?;
Ok(Artifact::new(destination))
}
.boxed()
}
}

View File

@ -4,6 +4,7 @@ use crate::project::gui::ide_desktop_from_context;
use crate::project::gui::GuiBuildWithWatchedWasm;
use crate::project::Context;
use crate::project::Gui;
use crate::project::IsArtifact;
use crate::source::WatchTargetJob;
use ide_ci::actions::artifacts::upload_compressed_directory;
@ -25,7 +26,7 @@ pub struct Artifact {
}
impl Artifact {
fn new(
pub fn new(
target_os: OS,
target_arch: Arch,
version: &Version,
@ -60,12 +61,14 @@ impl Artifact {
}
}
pub async fn upload_as_ci_artifact(&self) -> Result {
pub async fn upload_as_ci_artifact(&self, prefix: impl AsRef<str>) -> Result {
if is_in_env() {
upload_compressed_directory(&self.unpacked, format!("ide-unpacked-{TARGET_OS}"))
let prefix = prefix.as_ref();
upload_compressed_directory(&self.unpacked, format!("{prefix}-unpacked-{TARGET_OS}"))
.await?;
upload_single_file(&self.image, format!("ide-{TARGET_OS}")).await?;
upload_single_file(&self.image_checksum, format!("ide-{TARGET_OS}")).await?;
let packed_artifact_name = format!("{prefix}-{TARGET_OS}");
upload_single_file(&self.image, &packed_artifact_name).await?;
upload_single_file(&self.image_checksum, &packed_artifact_name).await?;
} else {
info!("Not in the CI environment, will not upload the artifacts.")
}
@ -91,14 +94,16 @@ impl Artifact {
#[derive(derivative::Derivative)]
#[derivative(Debug)]
pub struct BuildInput {
pub struct BuildInput<GuiArtifact> {
#[derivative(Debug(format_with = "std::fmt::Display::fmt"))]
pub version: Version,
#[derivative(Debug = "ignore")]
pub project_manager: BoxFuture<'static, Result<crate::project::backend::Artifact>>,
#[derivative(Debug = "ignore")]
pub gui: BoxFuture<'static, Result<crate::project::gui::Artifact>>,
pub gui: BoxFuture<'static, Result<GuiArtifact>>,
pub electron_target: Option<String>,
/// The name base used to generate CI run artifact names.
pub artifact_name: String,
}
#[derive(Clone, Copy, Debug)]
@ -117,10 +122,10 @@ impl Ide {
pub fn build(
&self,
context: &Context,
input: BuildInput,
input: BuildInput<impl IsArtifact>,
output_path: impl AsRef<Path> + Send + Sync + 'static,
) -> BoxFuture<'static, Result<Artifact>> {
let BuildInput { version, project_manager, gui, electron_target } = input;
let BuildInput { version, project_manager, gui, electron_target, artifact_name: _ } = input;
let ide_desktop = ide_desktop_from_context(context);
let target_os = self.target_os;
let target_arch = self.target_arch;
@ -155,30 +160,3 @@ impl Ide {
.boxed()
}
}
// impl IsTarget for Ide {
// type BuildInput = BuildInput;
// type Output = Artifact;
//
// fn artifact_name(&self) -> &str {
// // Version is not part of the name intentionally. We want to refer to PM bundles as
// // artifacts without knowing their version.
// static NAME: LazyLock<String> = LazyLock::new(|| format!("gui-{}", TARGET_OS));
// &*NAME
// }
//
// fn build(
// &self,
// input: Self::BuildInput,
// output_path: impl AsRef<Path> + Send + Sync + 'static,
// ) -> BoxFuture<'static, Result<Self::Output>> {
// let ide_desktop = crate::ide::web::IdeDesktop::new(&input.repo_root.app.ide_desktop);
// async move {
// let (gui, project_manager) = try_join(input.gui, input.project_manager).await?;
// ide_desktop.dist(&gui, &project_manager, &output_path).await?;
// Ok(Artifact::new(&input.version, output_path.as_ref()))
// }
// .boxed()
// }
// }

View File

@ -0,0 +1,9 @@
#[allow(unused_imports)]
use crate::prelude::*;
// ==============
// === Export ===
// ==============
pub use crate::project::ide::Artifact;

View File

@ -9,7 +9,6 @@ use crate::paths::TargetTriple;
use crate::project::Context;
use crate::project::IsArtifact;
use crate::project::IsTarget;
use crate::source::BuildTargetJob;
use crate::source::WithDestination;
use crate::version::Versions;
@ -42,7 +41,7 @@ impl IsTarget for Runtime {
fn build_internal(
&self,
context: Context,
job: BuildTargetJob<Self>,
job: WithDestination<Self::BuildInput>,
) -> BoxFuture<'static, Result<Self::Artifact>> {
let config = BuildConfigurationFlags {
build_engine_package: true,

View File

@ -7,7 +7,7 @@ use crate::project::Context;
use crate::project::IsArtifact;
use crate::project::IsTarget;
use crate::project::IsWatchable;
use crate::source::BuildTargetJob;
use crate::source::BuildSource;
use crate::source::WatchTargetJob;
use crate::source::WithDestination;
@ -205,9 +205,9 @@ impl IsTarget for Wasm {
fn build_internal(
&self,
context: Context,
job: BuildTargetJob<Self>,
job: WithDestination<Self::BuildInput>,
) -> BoxFuture<'static, Result<Self::Artifact>> {
let Context { octocrab: _, cache, upload_artifacts: _, repo_root } = context;
let Context { octocrab: _, cache, repo_root } = context;
let WithDestination { inner, destination } = job;
let span = info_span!("Building WASM.",
repo = %repo_root.display(),
@ -249,6 +249,7 @@ impl IsTarget for Wasm {
info!("Building wasm.");
let temp_dir = tempdir()?;
let temp_dist = RepoRootDistWasm::new_root(temp_dir.path());
crate::web::install(&repo_root).await?;
ensogl_pack::build(
ensogl_pack::WasmPackOutputs {
out_dir: temp_dist.path.clone(),
@ -327,11 +328,21 @@ impl IsWatchable for Wasm {
.instrument(debug_span!("Initial single build of WASM before setting up cargo-watch."));
async move {
let first_build_output = first_build_job.await?;
// Make sure that `npm install` was run, so we can spawned process to skip it.
// This prevents issues with multiple `npm install` invocations running in parallel.
let npm_install = crate::web::install(&context.repo_root);
let (first_build_output, npm_install) =
futures::future::join(first_build_job, npm_install).await;
npm_install?;
let first_build_output = first_build_output?;
let WatchTargetJob {
watch_input: WatchInput { cargo_watch_options: cargo_watch_flags },
build: WithDestination { inner, destination },
build:
WithDestination {
inner: BuildSource { input, should_upload_artifact: _ },
destination,
},
} = job;
let BuildInput {
crate_path,
@ -344,7 +355,7 @@ impl IsWatchable for Wasm {
uncollapsed_log_level,
wasm_size_limit,
system_shader_tools: _,
} = inner;
} = input;
let current_exe = std::env::current_exe()?;
@ -379,8 +390,8 @@ impl IsWatchable for Wasm {
.arg(current_exe)
.arg("--skip-version-check") // We already checked in the parent process.
.args(["--cache-path", context.cache.path().as_str()])
.args(["--upload-artifacts", context.upload_artifacts.to_string().as_str()])
.args(["--repo-path", context.repo_root.as_str()]);
.args(["--repo-path", context.repo_root.as_str()])
.args(["--skip-npm-install", "false"]);
// === Build Script command and its options ===
watch_cmd

View File

@ -10,6 +10,7 @@ use octocrab::models::RunId;
/// Denotes an external source from which a target artifact can be obtained.
#[derive(Clone, Derivative)]
#[derivative(Debug)]
pub enum ExternalSource {
@ -29,11 +30,23 @@ impl ExternalSource {
}
}
/// Describes how to build a target and whether to upload the resulting artifact.
#[derive(Clone, Debug)]
pub struct BuildSource<Target: IsTarget> {
/// Data needed to build the target.
pub input: Target::BuildInput,
/// Whether to upload the resulting artifact as CI artifact.
pub should_upload_artifact: bool,
}
/// Describes how to get a target.
#[derive(Derivative)]
#[derivative(Debug)]
pub enum Source<Target: IsTarget> {
/// Build the target locally from the sources.
#[derivative(Debug = "transparent")]
BuildLocally(Target::BuildInput),
BuildLocally(BuildSource<Target>),
/// Download the target from an external source.
#[derivative(Debug = "transparent")]
External(ExternalSource),
}
@ -83,6 +96,10 @@ impl<T: IsTarget> WithDestination<Source<T>> {
}
impl<T> WithDestination<T> {
pub fn new(inner: T, destination: impl Into<PathBuf>) -> Self {
Self { inner, destination: destination.into() }
}
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> WithDestination<U> {
WithDestination { inner: f(self.inner), destination: self.destination }
}
@ -90,7 +107,7 @@ impl<T> WithDestination<T> {
pub type GetTargetJob<Target> = WithDestination<Source<Target>>;
pub type FetchTargetJob = WithDestination<ExternalSource>;
pub type BuildTargetJob<Target> = WithDestination<<Target as IsTarget>::BuildInput>;
pub type BuildTargetJob<Target> = WithDestination<BuildSource<Target>>;
#[derive(Debug)]
pub struct WatchTargetJob<Target: IsWatchable> {

87
build/build/src/web.rs Normal file
View File

@ -0,0 +1,87 @@
//! Module for managing the web parts of our codebase.
//! This refers to JS/TS components, such as the Vue.js-based GUI, as well as the Electron client
//! application.
use crate::prelude::*;
use ide_ci::programs::Npm;
/// Result of root-level `npm install` call. Should not be accessed directly.
static ONCE_INSTALL: tokio::sync::OnceCell<Result> = tokio::sync::OnceCell::const_new();
/// This method invokes `npm install` in the root repository.
///
/// It ensures that at most one such invocation is running at any given time.
/// If an invocation is already running, it waits for it to finish and then
/// shares its result.
///
/// This method relies on the internal global state. It must not be called multiple times
/// with different `repo_root` arguments.
///
/// It is useful, because otherwise the build script might end up invoking `npm install` multiple
/// times, sometimes even in parallel. Unfortunately, in such cases, `npm` might fail with errors.
pub fn install(repo_root: impl AsRef<Path>) -> BoxFuture<'static, Result> {
let root_path = repo_root.as_ref().to_owned();
async move {
let ret = ONCE_INSTALL
.get_or_init(async || Npm.cmd()?.with_current_dir(&root_path).install().run_ok().await)
.await;
ret.as_ref().copied().map_err(|e| anyhow!("Failed to install NPM dependencies: {e}"))
}
.boxed()
}
/// Mark the root repository's NPM as installed.
///
/// If invoked before `install`, any subsequent `install` call will return `Ok`.
/// If it was already installed and failed, the failure will still be returned.
pub fn assume_installed() {
let _ = ONCE_INSTALL.set(Ok(())).inspect_err(|e| {
warn!("Failed to mark NPM as installed, due to an error during a previous run: {e}");
});
}
/// The scripts that can be invoked in the root repository's NPM.
///
/// The list should be kept in sync with the `scripts` section of the root repository's
/// `package.json`.
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, strum::AsRefStr)]
#[strum(serialize_all = "kebab-case")]
pub enum Script {
Format,
Prettier,
Lint,
Test,
Typecheck,
CiCheck,
}
/// Invoke the given script in the context of the root repository's NPM.
pub fn run_script(repo_root: impl AsRef<Path>, script: Script) -> BoxFuture<'static, Result> {
let root_path = repo_root.as_ref().to_owned();
async move { Npm.cmd()?.with_current_dir(&root_path).run(script.as_ref()).run_ok().await }
.boxed()
}
/// The list of NPM workspaces that are part of the root repository.
#[derive(Debug, Clone, Copy, PartialEq, Eq, strum::AsRefStr)]
#[strum(serialize_all = "kebab-case")]
pub enum Workspace {
EnsoIdeDesktop,
Enso,
EnsoContent,
EnsoDashboard,
EnsoIcons,
EnsoAuthentication,
EnsoGui2,
EnsoglRunner,
}
impl AsRef<OsStr> for Workspace {
fn as_ref(&self) -> &OsStr {
AsRef::<str>::as_ref(self).as_ref()
}
}

View File

@ -19,6 +19,8 @@ pub mod prelude {
/// Generate the comment that is at the top of each generated workflow file.
fn preamble(source: &str) -> String {
// To make output consistent across platforms.
let source = source.replace('\\', "/");
format!(
"# This file is auto-generated. Do not edit it manually!\n\
# Edit the {source} module instead and run `cargo run --package {}`.",

View File

@ -246,12 +246,21 @@ pub trait IsCommandWrapper {
/// Value-based variant of [`Self::current_dir`], for convenience.
fn with_current_dir(self, dir: impl AsRef<Path>) -> Self
where Self: Sized {
let mut this = self;
this.current_dir(dir);
this
}
/// Value-based variant of [`Self::with_stdin`], for convenience.
fn with_stdin(self, stdin: Stdio) -> Self
where Self: Sized {
let mut this = self;
this.stdin(stdin);
this
}
}
impl<T: BorrowMut<tokio::process::Command>> IsCommandWrapper for T {

View File

@ -20,7 +20,9 @@ pub mod backend;
pub mod engine;
pub mod git_clean;
pub mod gui;
pub mod gui2;
pub mod ide;
pub mod ide2;
pub mod java_gen;
pub mod project_manager;
pub mod release;
@ -75,10 +77,10 @@ pub trait IsTargetSource {
const SOURCE_NAME: &'static str;
const PATH_NAME: &'static str;
const OUTPUT_PATH_NAME: &'static str;
// const UPLOAD_ASSET_NAME: &'static str;
const RUN_ID_NAME: &'static str;
const RELEASE_DESIGNATOR_NAME: &'static str;
const ARTIFACT_NAME_NAME: &'static str;
const UPLOAD_ARTIFACT_NAME: &'static str;
const DEFAULT_OUTPUT_PATH: &'static str;
type BuildInput: Clone + Debug + PartialEq + Args + Send + Sync;
@ -99,6 +101,7 @@ macro_rules! source_args_hlp {
const RUN_ID_NAME: &'static str = concat!($prefix, "-", "run-id");
const RELEASE_DESIGNATOR_NAME: &'static str = concat!($prefix, "-", "release");
const ARTIFACT_NAME_NAME: &'static str = concat!($prefix, "-", "artifact-name");
const UPLOAD_ARTIFACT_NAME: &'static str = concat!($prefix, "-", "upload-artifact");
const DEFAULT_OUTPUT_PATH: &'static str = concat!("dist/", $prefix);
type BuildInput = $inputs;
@ -111,8 +114,10 @@ macro_rules! source_args_hlp {
pub enum Target {
/// Build/Test the Rust part of the GUI.
Wasm(wasm::Target),
/// Build/Run GUI that consists of WASM and JS parts. This is what we deploy to cloud.
/// Build/Run the legacy Rust-based GUI that consists of WASM and JS parts.
Gui(gui::Target),
/// Build/Run the new, Vue-based GUI.
Gui2(gui2::Target),
/// Enso Engine Runtime.
Runtime(runtime::Target),
// /// Project Manager package (just the binary, no Engine)
@ -121,8 +126,10 @@ pub enum Target {
// Engine(engine::Target),
/// Build/Get Project Manager bundle (includes Enso Engine with GraalVM Runtime).
Backend(backend::Target),
/// Build/Run/Test IDE bundle (includes GUI and Project Manager).
/// Build/Run/Test IDE bundle (includes Rust-based GUI and Project Manager).
Ide(ide::Target),
/// Build/Run/Test IDE bundle (includes Vue-based GUI and Project Manager).
Ide2(ide2::Target),
/// Clean the repository. Keeps the IntelliJ's .idea directory intact. WARNING: This removes
/// files that are not under version control in the repository subtree.
GitClean(git_clean::Options),
@ -167,10 +174,9 @@ pub struct Cli {
#[clap(long, global = true, enso_env())]
pub skip_version_check: bool,
/// Whether built artifacts should be uploaded as part of CI run. Ignored in non-CI
/// environment.
#[clap(long, global = true, hide = !ide_ci::actions::workflow::is_in_env(), parse(try_from_str), default_value_t = true, enso_env())]
pub upload_artifacts: bool,
/// Assume that `npm install` was already run in the repository root and skip it.
#[clap(long, global = true, enso_env())]
pub skip_npm_install: bool,
#[clap(subcommand)]
pub target: Target,
@ -214,13 +220,10 @@ pub struct Source<Target: IsTargetSource> {
/// Used when `SourceKind::Build` is used.
#[clap(flatten)]
pub build_args: Target::BuildInput,
pub build_args: BuildDescription<Target>,
#[clap(flatten)]
pub output_path: OutputPath<Target>,
//
// #[clap(name = Target::UPLOAD_ASSET_NAME, long)]
// pub upload_asset: bool,
}
/// Discriminator denoting how some target artifact should be obtained.
@ -258,11 +261,20 @@ impl<Target: IsTargetSource> AsRef<Path> for OutputPath<Target> {
}
}
#[derive(Args, Clone, PartialEq, Derivative)]
#[derivative(Debug)]
pub struct BuildDescription<Target: IsTargetSource> {
#[clap(flatten)]
pub input: Target::BuildInput,
#[clap(name = Target::UPLOAD_ARTIFACT_NAME, long, enso_env(), default_value_t = ide_ci::actions::workflow::is_in_env())]
pub upload_artifact: bool,
}
#[derive(Args, Clone, PartialEq, Derivative)]
#[derivative(Debug)]
pub struct BuildJob<Target: IsTargetSource> {
#[clap(flatten)]
pub input: Target::BuildInput,
pub input: BuildDescription<Target>,
#[clap(flatten)]
pub output_path: OutputPath<Target>,
}

35
build/cli/src/arg/gui2.rs Normal file
View File

@ -0,0 +1,35 @@
use enso_build::prelude::*;
use crate::arg::BuildJob;
use crate::arg::Source;
use crate::source_args_hlp;
use clap::Args;
use clap::Subcommand;
use enso_build::project::gui2::Gui2;
source_args_hlp!(Gui2, "gui2", BuildInput);
#[derive(Args, Clone, Copy, Debug, PartialEq)]
pub struct BuildInput {}
#[derive(Subcommand, Clone, Debug, PartialEq)]
pub enum Command {
/// Builds the GUI from the local sources.
Build(BuildJob<Gui2>),
/// Gets the GUI, either by compiling it from scratch or downloading from an external source.
Get(Source<Gui2>),
/// Runs the GUI's unit tests.
Test,
/// Run linter on the GUI's sources.
Lint,
}
#[derive(Args, Clone, Debug)]
pub struct Target {
/// Command for GUI package.
#[clap(subcommand)]
pub command: Command,
}

View File

@ -1,5 +1,6 @@
use crate::prelude::*;
use crate::arg::IsTargetSource;
use crate::arg::OutputPath;
use crate::arg::Source;
use crate::arg::WatchJob;
@ -14,10 +15,10 @@ use octocrab::models::ReleaseId;
source_args_hlp!(Target, "ide", BuildInput);
source_args_hlp!(Target, "ide", BuildInput<Gui>);
#[derive(Args, Clone, Debug, PartialEq)]
pub struct BuildInput {
pub struct BuildInput<Gui: IsTargetSource> {
#[clap(flatten)]
pub gui: Source<Gui>,
#[clap(flatten)]
@ -36,18 +37,18 @@ pub enum Command {
/// application.
Build {
#[clap(flatten)]
params: BuildInput,
params: BuildInput<Gui>,
},
Upload {
#[clap(flatten)]
params: BuildInput,
params: BuildInput<Gui>,
#[clap(long, env = *enso_build::env::ENSO_RELEASE_ID)]
release_id: ReleaseId,
},
/// Like `Build` but automatically starts the IDE.
Start {
#[clap(flatten)]
params: BuildInput,
params: BuildInput<Gui>,
/// Additional option to be passed to Enso IDE. Can be used multiple times to pass many
/// arguments.
#[clap(long, allow_hyphen_values = true, enso_env())]

29
build/cli/src/arg/ide2.rs Normal file
View File

@ -0,0 +1,29 @@
use crate::prelude::*;
use crate::source_args_hlp;
use clap::Args;
use clap::Subcommand;
use enso_build::project::gui2::Gui2;
source_args_hlp!(Target, "ide2", BuildInput);
pub type BuildInput = crate::arg::ide::BuildInput<Gui2>;
#[derive(Subcommand, Clone, Debug)]
pub enum Command {
/// Builds both Project Manager and GUI, puts them together into a single, client Electron
/// application.
Build {
#[clap(flatten)]
params: BuildInput,
},
}
#[derive(Args, Clone, Debug)]
pub struct Target {
#[clap(subcommand)]
pub command: Command,
}

View File

@ -38,9 +38,11 @@ use crate::arg::BuildJob;
use crate::arg::Cli;
use crate::arg::IsTargetSource;
use crate::arg::IsWatchableSource;
use crate::arg::OutputPath;
use crate::arg::Target;
use crate::arg::WatchJob;
use anyhow::Context;
use arg::BuildDescription;
use clap::Parser;
use derivative::Derivative;
use enso_build::context::BuildContext;
@ -53,15 +55,20 @@ use enso_build::project::backend;
use enso_build::project::backend::Backend;
use enso_build::project::gui;
use enso_build::project::gui::Gui;
use enso_build::project::gui2;
use enso_build::project::gui2::Gui2;
use enso_build::project::ide;
use enso_build::project::ide::Ide;
use enso_build::project::ide2;
use enso_build::project::runtime;
use enso_build::project::runtime::Runtime;
use enso_build::project::wasm;
use enso_build::project::wasm::Wasm;
use enso_build::project::IsArtifact;
use enso_build::project::IsTarget;
use enso_build::project::IsWatchable;
use enso_build::project::IsWatcher;
use enso_build::source::BuildSource;
use enso_build::source::BuildTargetJob;
use enso_build::source::CiRunSource;
use enso_build::source::ExternalSource;
@ -85,7 +92,6 @@ use ide_ci::programs::git;
use ide_ci::programs::git::clean;
use ide_ci::programs::rustc;
use ide_ci::programs::Cargo;
use ide_ci::programs::Npm;
use std::time::Duration;
use tempfile::tempdir;
use tokio::process::Child;
@ -131,7 +137,6 @@ impl Processor {
inner: project::Context {
cache: Cache::new(&cli.cache_path).await?,
octocrab,
upload_artifacts: cli.upload_artifacts,
repo_root: enso_build::paths::new_repo_root(absolute_repo_path, &triple),
},
triple,
@ -154,9 +159,13 @@ impl Processor {
{
let span = info_span!("Resolving.", ?target, ?source).entered();
let destination = source.output_path.output_path;
let should_upload_artifact = source.build_args.upload_artifact;
let source = match source.source {
arg::SourceKind::Build =>
T::resolve(self, source.build_args).map_ok(Source::BuildLocally).boxed(),
arg::SourceKind::Build => T::resolve(self, source.build_args.input)
.map_ok(move |input| {
Source::BuildLocally(BuildSource { input, should_upload_artifact })
})
.boxed(),
arg::SourceKind::Local =>
ok_ready_boxed(Source::External(ExternalSource::LocalFile(source.path))),
arg::SourceKind::CiRun => {
@ -243,10 +252,16 @@ impl Processor {
&self,
job: BuildJob<T>,
) -> BoxFuture<'static, Result<BuildTargetJob<T>>> {
let BuildJob { input, output_path } = job;
let BuildJob { input: BuildDescription { input, upload_artifact }, output_path } = job;
let input = self.resolve_inputs::<T>(input);
async move {
Ok(WithDestination { destination: output_path.output_path, inner: input.await? })
Ok(WithDestination::new(
BuildSource {
input: input.await?,
should_upload_artifact: upload_artifact,
},
output_path.output_path,
))
}
.boxed()
}
@ -320,17 +335,6 @@ impl Processor {
}
}
// pub fn handle_engine(&self, engine: arg::engine::Target) -> BoxFuture<'static, Result> {
// self.get(engine.source).void_ok().boxed()
// }
//
// pub fn handle_project_manager(
// &self,
// project_manager: arg::project_manager::Target,
// ) -> BoxFuture<'static, Result> {
// self.get(project_manager.source).void_ok().boxed()
// }
pub fn handle_gui(&self, gui: arg::gui::Target) -> BoxFuture<'static, Result> {
match gui.command {
arg::gui::Command::Build(job) => self.build(job),
@ -339,6 +343,15 @@ impl Processor {
}
}
pub fn handle_gui2(&self, gui: arg::gui2::Target) -> BoxFuture<'static, Result> {
match gui.command {
arg::gui2::Command::Build(job) => self.build(job),
arg::gui2::Command::Get(source) => self.get(source).void_ok().boxed(),
arg::gui2::Command::Test => gui2::unit_tests(&self.repo_root),
arg::gui2::Command::Lint => gui2::lint(&self.repo_root),
}
}
pub fn handle_runtime(&self, gui: arg::runtime::Target) -> BoxFuture<'static, Result> {
// todo!()
match gui.command {
@ -439,8 +452,7 @@ impl Processor {
};
let context = self.prepare_backend_context(config);
async move {
let mut context = context.await?;
context.upload_artifacts = true;
let context = context.await?;
context.build().await
}
.void_ok()
@ -461,7 +473,7 @@ impl Processor {
let paths = paths?;
let inner = crate::project::Context {
repo_root: paths.repo_root.clone(),
upload_artifacts: true,
// upload_artifacts: true,
octocrab,
cache: Cache::new_default().await?,
};
@ -472,9 +484,9 @@ impl Processor {
pub fn handle_ide(&self, ide: arg::ide::Target) -> BoxFuture<'static, Result> {
match ide.command {
arg::ide::Command::Build { params } => self.build_ide(params).void_ok().boxed(),
arg::ide::Command::Build { params } => self.build_old_ide(params).void_ok().boxed(),
arg::ide::Command::Upload { params, release_id } => {
let build_job = self.build_ide(params);
let build_job = self.build_old_ide(params);
let release = ide_ci::github::release::Handle::new(
&self.octocrab,
self.remote_repo.clone(),
@ -489,7 +501,7 @@ impl Processor {
.boxed()
}
arg::ide::Command::Start { params, ide_option } => {
let build_job = self.build_ide(params);
let build_job = self.build_old_ide(params);
async move {
let ide = build_job.await?;
ide.start_unpacked(ide_option).run_ok().await?;
@ -547,6 +559,12 @@ impl Processor {
}
}
pub fn handle_ide2(&self, ide: arg::ide2::Target) -> BoxFuture<'static, Result> {
match ide.command {
arg::ide2::Command::Build { params } => self.build_new_ide(params).void_ok().boxed(),
}
}
/// Spawns a Project Manager.
pub fn spawn_project_manager(
&self,
@ -566,10 +584,27 @@ impl Processor {
}
.boxed()
}
pub fn build_ide(
&self,
params: arg::ide::BuildInput,
input: ide::BuildInput<impl IsArtifact>,
output_path: OutputPath<arg::ide::Target>,
) -> BoxFuture<'static, Result<ide::Artifact>> {
let target = Ide { target_os: self.triple.os, target_arch: self.triple.arch };
let artifact_name_prefix = input.artifact_name.clone();
let build_job = target.build(&self.context, input, output_path);
async move {
let artifacts = build_job.await?;
if is_in_env() {
artifacts.upload_as_ci_artifact(artifact_name_prefix).await?;
}
Ok(artifacts)
}
.boxed()
}
pub fn build_old_ide(
&self,
params: arg::ide::BuildInput<Gui>,
) -> BoxFuture<'static, Result<ide::Artifact>> {
let arg::ide::BuildInput { gui, project_manager, output_path, electron_target } = params;
let input = ide::BuildInput {
@ -577,17 +612,39 @@ impl Processor {
project_manager: self.get(project_manager),
version: self.triple.versions.version.clone(),
electron_target,
artifact_name: "ide".into(),
};
let target = Ide { target_os: self.triple.os, target_arch: self.triple.arch };
let build_job = target.build(&self.context, input, output_path);
async move {
let artifacts = build_job.await?;
if is_in_env() {
artifacts.upload_as_ci_artifact().await?;
self.build_ide(input, output_path)
}
pub fn build_new_ide(
&self,
params: arg::ide2::BuildInput,
) -> BoxFuture<'static, Result<ide2::Artifact>> {
let arg::ide::BuildInput { gui, project_manager, output_path, electron_target } = params;
let build_info_get = self.js_build_info();
let build_info_path = self.context.inner.repo_root.join(&*enso_build::ide::web::BUILD_INFO);
let build_info = async move {
let build_info = build_info_get.await?;
build_info_path.write_as_json(&build_info)
};
let gui = self.get(gui);
let input = ide::BuildInput {
gui: async move {
build_info.await?;
gui.await
}
Ok(artifacts)
}
.boxed()
.boxed(),
project_manager: self.get(project_manager),
version: self.triple.versions.version.clone(),
electron_target,
artifact_name: "ide2".into(),
};
self.build_ide(input, output_path)
}
pub fn target<Target: Resolvable>(&self) -> Result<Target> {
@ -655,6 +712,19 @@ impl Resolvable for Gui {
}
}
impl Resolvable for Gui2 {
fn prepare_target(_context: &Processor) -> Result<Self> {
Ok(Gui2)
}
fn resolve(
_ctx: &Processor,
_from: <Self as IsTargetSource>::BuildInput,
) -> BoxFuture<'static, Result<<Self as IsTarget>::BuildInput>> {
ok_ready_boxed(())
}
}
impl Resolvable for Runtime {
fn prepare_target(_context: &Processor) -> Result<Self> {
Ok(Runtime {})
@ -696,42 +766,9 @@ impl Resolvable for Backend {
Ok(backend::BuildInput { external_runtime, versions })
})
.boxed()
// ok_ready_boxed(backend::BuildInput { versions: ctx.triple.versions.clone() })
}
}
// impl Resolvable for ProjectManager {
// fn prepare_target(_context: &Processor) -> Result<Self> {
// Ok(ProjectManager)
// }
//
// fn resolve(
// ctx: &Processor,
// _from: <Self as IsTargetSource>::BuildInput,
// ) -> BoxFuture<'static, Result<<Self as IsTarget>::BuildInput>> {
// ok_ready_boxed(project_manager::BuildInput {
// repo_root: ctx.repo_root().path,
// versions: ctx.triple.versions.clone(),
// })
// }
// }
//
// impl Resolvable for Engine {
// fn prepare_target(_context: &Processor) -> Result<Self> {
// Ok(Engine)
// }
//
// fn resolve(
// ctx: &Processor,
// _from: <Self as IsTargetSource>::BuildInput,
// ) -> BoxFuture<'static, Result<<Self as IsTarget>::BuildInput>> {
// ok_ready_boxed(engine::BuildInput {
// repo_root: ctx.repo_root().path,
// versions: ctx.triple.versions.clone(),
// })
// }
// }
pub trait WatchResolvable: Resolvable + IsWatchableSource + IsWatchable {
fn resolve_watch(
ctx: &Processor,
@ -777,6 +814,10 @@ pub async fn main_internal(config: Option<enso_build::config::Config>) -> Result
debug!("Parsed CLI arguments: {cli:#?}");
if cli.skip_npm_install {
enso_build::web::assume_installed();
}
if !cli.skip_version_check {
// Let's be helpful!
let error_message = "Program requirements were not fulfilled. Please do one of the \
@ -796,13 +837,14 @@ pub async fn main_internal(config: Option<enso_build::config::Config>) -> Result
match cli.target {
Target::Wasm(wasm) => ctx.handle_wasm(wasm).await?,
Target::Gui(gui) => ctx.handle_gui(gui).await?,
Target::Gui2(gui2) => ctx.handle_gui2(gui2).await?,
Target::Runtime(runtime) => ctx.handle_runtime(runtime).await?,
// Target::ProjectManager(project_manager) =>
// ctx.handle_project_manager(project_manager).await?,
// Target::Engine(engine) => ctx.handle_engine(engine).await?,
Target::Backend(backend) => ctx.handle_backend(backend).await?,
Target::Ide(ide) => ctx.handle_ide(ide).await?,
// TODO: consider if out-of-source ./dist should be removed
Target::Ide2(ide2) => ctx.handle_ide2(ide2).await?,
Target::GitClean(options) => {
let crate::arg::git_clean::Options { dry_run, cache, build_script } = options;
let mut exclusions = vec![".idea"];
@ -852,12 +894,13 @@ pub async fn main_internal(config: Option<enso_build::config::Config>) -> Result
.run_ok()
.await?;
Npm.cmd()?.install().run_ok().await?;
Npm.cmd()?.run("ci-check").run_ok().await?;
enso_build::web::install(&ctx.repo_root).await?;
enso_build::web::run_script(&ctx.repo_root, enso_build::web::Script::CiCheck).await?;
}
Target::Fmt => {
Npm.cmd()?.install().run_ok().await?;
let prettier = Npm.cmd()?.run("format").run_ok();
enso_build::web::install(&ctx.repo_root).await?;
let prettier =
enso_build::web::run_script(&ctx.repo_root, enso_build::web::Script::Format);
let our_formatter =
enso_formatter::process_path(&ctx.repo_root, enso_formatter::Action::Format);
let (r1, r2) = join!(prettier, our_formatter).await;

View File

@ -61,7 +61,7 @@
//! 1. If the `dist/index.js` file does not exist, or its modification date is older than
//! `this_crate/js` sources:
//!
//! 1. `npm run install` is run in the `this_crate/js` directory.
//! 1. `npm install` is assumed to have been already run in the `this_crate/js` directory.
//!
//! 2. The `this_crate/js/runner` is compiled to `target/ensogl-pack/dist/index.cjs`. This is the
//! main file which is capable of loading WASM file, displaying a loading screen, running
@ -351,7 +351,6 @@ pub async fn compile_this_crate_ts_sources(paths: &Paths) -> Result<()> {
println!("compile_this_crate_ts_sources");
if check_if_ts_needs_rebuild(paths)? {
info!("EnsoGL Pack TypeScript sources changed, recompiling.");
ide_ci::programs::Npm.cmd()?.install().current_dir(&paths.workspace).run_ok().await?;
let run_script = async move |script_name, script_args: &[&str]| {
ide_ci::programs::Npm
.cmd()?
@ -378,6 +377,7 @@ pub async fn compile_this_crate_ts_sources(paths: &Paths) -> Result<()> {
}
/// Run wasm-pack to build the wasm artifact.
#[context("Failed to run wasm-pack.")]
pub async fn run_wasm_pack(
paths: &Paths,
provider: impl FnOnce(WasmPackOutputs) -> Result<WasmPackCommand>,

45
package-lock.json generated
View File

@ -3021,6 +3021,51 @@
}
}
},
"node_modules/@swc/core-darwin-arm64": {
"version": "1.3.85",
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-darwin-x64": {
"version": "1.3.85",
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-x64-gnu": {
"version": "1.3.85",
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0 AND MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-win32-x64-msvc": {
"version": "1.3.85",
"cpu": [