mirror of
https://github.com/element-hq/element-desktop.git
synced 2026-01-05 22:18:16 -05:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e28c141ab |
@@ -1,22 +0,0 @@
|
||||
module.exports = {
|
||||
plugins: ["matrix-org"],
|
||||
extends: [".eslintrc.js"],
|
||||
parserOptions: {
|
||||
project: ["hak/tsconfig.json"],
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ["hak/**/*.ts"],
|
||||
extends: ["plugin:matrix-org/typescript"],
|
||||
rules: {
|
||||
// Things we do that break the ideal style
|
||||
"prefer-promise-reject-errors": "off",
|
||||
"quotes": "off",
|
||||
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
// We're okay with assertion errors when we ask for them
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -1,22 +0,0 @@
|
||||
module.exports = {
|
||||
plugins: ["matrix-org"],
|
||||
extends: [".eslintrc.js"],
|
||||
parserOptions: {
|
||||
project: ["scripts/tsconfig.json"],
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ["scripts/**/*.ts"],
|
||||
extends: ["plugin:matrix-org/typescript"],
|
||||
rules: {
|
||||
// Things we do that break the ideal style
|
||||
"prefer-promise-reject-errors": "off",
|
||||
"quotes": "off",
|
||||
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
// We're okay with assertion errors when we ask for them
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -1,22 +0,0 @@
|
||||
module.exports = {
|
||||
plugins: ["matrix-org"],
|
||||
extends: [".eslintrc.js"],
|
||||
parserOptions: {
|
||||
project: ["test/tsconfig.json"],
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ["test/**/*.ts"],
|
||||
extends: ["plugin:matrix-org/typescript"],
|
||||
rules: {
|
||||
// Things we do that break the ideal style
|
||||
"prefer-promise-reject-errors": "off",
|
||||
"quotes": "off",
|
||||
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
// We're okay with assertion errors when we ask for them
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
32
.eslintrc.js
32
.eslintrc.js
@@ -1,9 +1,10 @@
|
||||
module.exports = {
|
||||
plugins: ["matrix-org"],
|
||||
extends: ["plugin:matrix-org/javascript"],
|
||||
extends: [
|
||||
"plugin:matrix-org/javascript",
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 2021,
|
||||
project: ["tsconfig.json"],
|
||||
},
|
||||
env: {
|
||||
es6: true,
|
||||
@@ -11,27 +12,24 @@ module.exports = {
|
||||
// we also have some browser code (ie. the preload script)
|
||||
browser: true,
|
||||
},
|
||||
// NOTE: These rules are frozen and new rules should not be added here.
|
||||
// New changes belong in https://github.com/matrix-org/eslint-plugin-matrix-org/
|
||||
rules: {
|
||||
"quotes": "off",
|
||||
"indent": "off",
|
||||
"prefer-promise-reject-errors": "off",
|
||||
"no-async-promise-executor": "off",
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ["src/**/*.ts"],
|
||||
extends: ["plugin:matrix-org/typescript"],
|
||||
rules: {
|
||||
// Things we do that break the ideal style
|
||||
"prefer-promise-reject-errors": "off",
|
||||
"quotes": "off",
|
||||
overrides: [{
|
||||
files: ["src/**/*.{ts,tsx}"],
|
||||
extends: [
|
||||
"plugin:matrix-org/typescript",
|
||||
],
|
||||
rules: {
|
||||
// Things we do that break the ideal style
|
||||
"prefer-promise-reject-errors": "off",
|
||||
"quotes": "off",
|
||||
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
// We're okay with assertion errors when we ask for them
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
},
|
||||
// We disable this while we're transitioning
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
},
|
||||
],
|
||||
}],
|
||||
};
|
||||
|
||||
5
.github/CODEOWNERS
vendored
5
.github/CODEOWNERS
vendored
@@ -1,4 +1 @@
|
||||
* @vector-im/element-web
|
||||
/.github/workflows/** @vector-im/element-web-app-team
|
||||
/package.json @vector-im/element-web-app-team
|
||||
/yarn.lock @vector-im/element-web-app-team
|
||||
* @vector-im/element-web
|
||||
|
||||
76
.github/ISSUE_TEMPLATE/bug-desktop.yml
vendored
76
.github/ISSUE_TEMPLATE/bug-desktop.yml
vendored
@@ -1,76 +0,0 @@
|
||||
name: Bug report for the Element desktop app (not in a browser)
|
||||
description: File a bug report if you are using the desktop Element application.
|
||||
labels: [T-Defect]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
|
||||
Please report security issues by email to security@matrix.org
|
||||
- type: textarea
|
||||
id: reproduction-steps
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: Please attach screenshots, videos or logs if you can.
|
||||
placeholder: Tell us what you see!
|
||||
value: |
|
||||
1. Where are you starting? What can you see?
|
||||
2. What do you click?
|
||||
3. More steps…
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: result
|
||||
attributes:
|
||||
label: Outcome
|
||||
placeholder: Tell us what went wrong
|
||||
value: |
|
||||
#### What did you expect?
|
||||
|
||||
#### What happened instead?
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: os
|
||||
attributes:
|
||||
label: Operating system
|
||||
placeholder: Windows, macOS, Ubuntu, Arch Linux…
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Application version
|
||||
description: You can find the version information in Settings -> Help & About.
|
||||
placeholder: e.g. Element version 1.7.34, olm version 3.2.3
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: source
|
||||
attributes:
|
||||
label: How did you install the app?
|
||||
description: Where did you install the app from? Please give a link or a description.
|
||||
placeholder: e.g. From https://element.io/get-started
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: homeserver
|
||||
attributes:
|
||||
label: Homeserver
|
||||
description: |
|
||||
Which server is your account registered on? If it is a local or non-public homeserver, please tell us what is the homeserver implementation (ex: Synapse/Dendrite/etc.) and the version.
|
||||
placeholder: e.g. matrix.org or Synapse 1.50.0rc1
|
||||
validations:
|
||||
required: false
|
||||
- type: dropdown
|
||||
id: rageshake
|
||||
attributes:
|
||||
label: Will you send logs?
|
||||
description: |
|
||||
Did you know that you can send a /rageshake command from your application to submit logs for this issue? Trigger the defect, then type `/rageshake` into the message input area followed by a description of the problem and send the command. You will be able to add a link to this defect report and submit anonymous logs to the developers.
|
||||
options:
|
||||
- "Yes"
|
||||
- "No"
|
||||
validations:
|
||||
required: true
|
||||
1
.github/ISSUE_TEMPLATE/config.yml
vendored
1
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1 +0,0 @@
|
||||
blank_issues_enabled: false
|
||||
36
.github/ISSUE_TEMPLATE/enhancement.yml
vendored
36
.github/ISSUE_TEMPLATE/enhancement.yml
vendored
@@ -1,36 +0,0 @@
|
||||
name: Enhancement request
|
||||
description: Do you have a suggestion or feature request?
|
||||
labels: [T-Enhancement]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for taking the time to propose an enhancement to an existing feature. If you would like to propose a new feature or a major cross-platform change, please [start a discussion here](https://github.com/vector-im/element-meta/discussions/new?category=ideas).
|
||||
- type: textarea
|
||||
id: usecase
|
||||
attributes:
|
||||
label: Your use case
|
||||
description: What would you like to be able to do? Please feel welcome to include screenshots or mock ups.
|
||||
placeholder: Tell us what you would like to do!
|
||||
value: |
|
||||
#### What would you like to do?
|
||||
|
||||
#### Why would you like to do it?
|
||||
|
||||
#### How would you like to achieve it?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: alternative
|
||||
attributes:
|
||||
label: Have you considered any alternatives?
|
||||
placeholder: A clear and concise description of any alternative solutions or features you've considered.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: additional-context
|
||||
attributes:
|
||||
label: Additional context
|
||||
placeholder: Is there anything else you'd like to add?
|
||||
validations:
|
||||
required: false
|
||||
13
.github/PULL_REQUEST_TEMPLATE.md
vendored
13
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,13 +0,0 @@
|
||||
<!-- Thanks for submitting a PR! Please ensure the following requirements are met in order for us to review your PR -->
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] Ensure your code works with manual testing
|
||||
- [ ] Linter and other CI checks pass
|
||||
- [ ] Sign-off given on the changes (see [CONTRIBUTING.md](https://github.com/vector-im/element-desktop/blob/develop/CONTRIBUTING.md))
|
||||
|
||||
<!--
|
||||
If you would like to specify text for the changelog entry other than your PR title, add the following:
|
||||
|
||||
Notes: Add super cool feature
|
||||
-->
|
||||
4
.github/renovate.json
vendored
4
.github/renovate.json
vendored
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": ["github>matrix-org/renovate-config-element-web"]
|
||||
}
|
||||
30
.github/workflows/backport.yml
vendored
30
.github/workflows/backport.yml
vendored
@@ -1,30 +0,0 @@
|
||||
name: Backport
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- closed
|
||||
- labeled
|
||||
branches:
|
||||
- develop
|
||||
|
||||
jobs:
|
||||
backport:
|
||||
name: Backport
|
||||
runs-on: ubuntu-latest
|
||||
# Only react to merged PRs for security reasons.
|
||||
# See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target.
|
||||
if: >
|
||||
github.event.pull_request.merged
|
||||
&& (
|
||||
github.event.action == 'closed'
|
||||
|| (
|
||||
github.event.action == 'labeled'
|
||||
&& contains(github.event.label.name, 'backport')
|
||||
)
|
||||
)
|
||||
steps:
|
||||
- uses: tibdex/backport@9565281eda0731b1d20c4025c43339fb0a23812e # v2
|
||||
with:
|
||||
labels_template: "<%= JSON.stringify([...labels, 'X-Release-Blocker']) %>"
|
||||
# We can't use GITHUB_TOKEN here or CI won't run on the new PR
|
||||
github_token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
173
.github/workflows/build_and_deploy.yaml
vendored
173
.github/workflows/build_and_deploy.yaml
vendored
@@ -1,173 +0,0 @@
|
||||
name: Build and Deploy
|
||||
on:
|
||||
# Nightly build
|
||||
schedule:
|
||||
- cron: "0 9 * * *"
|
||||
# Release build
|
||||
release:
|
||||
types: [published]
|
||||
# Manual nightly & release
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
mode:
|
||||
description: What type of build to trigger. Release builds MUST be ran from the `master` branch.
|
||||
required: true
|
||||
default: nightly
|
||||
type: choice
|
||||
options:
|
||||
- nightly
|
||||
- release
|
||||
macos:
|
||||
description: Build macOS
|
||||
required: true
|
||||
type: boolean
|
||||
default: true
|
||||
windows:
|
||||
description: Build Windows
|
||||
required: true
|
||||
type: boolean
|
||||
default: true
|
||||
linux:
|
||||
description: Build Linux
|
||||
required: true
|
||||
type: boolean
|
||||
default: true
|
||||
deploy:
|
||||
description: Deploy artifacts
|
||||
required: true
|
||||
type: boolean
|
||||
default: true
|
||||
run-name: Element ${{ inputs.mode != 'release' && github.event_name != 'release' && 'Nightly' || 'Desktop' }}
|
||||
concurrency: ${{ github.workflow }}
|
||||
env:
|
||||
R2_BUCKET: ${{ vars.R2_BUCKET }}
|
||||
jobs:
|
||||
prepare:
|
||||
uses: ./.github/workflows/build_prepare.yaml
|
||||
with:
|
||||
config: element.io/${{ inputs.mode || (github.event_name == 'release' && 'release') || 'nightly' }}
|
||||
version: ${{ (inputs.mode != 'release' && github.event_name != 'release') && 'develop' || '' }}
|
||||
nightly: ${{ inputs.mode != 'release' && github.event_name != 'release' }}
|
||||
secrets:
|
||||
CF_R2_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
|
||||
CF_R2_TOKEN: ${{ secrets.CF_R2_TOKEN }}
|
||||
|
||||
windows:
|
||||
if: github.event_name != 'workflow_dispatch' || inputs.windows
|
||||
needs: prepare
|
||||
name: Windows ${{ matrix.arch }}
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x86, x64]
|
||||
uses: ./.github/workflows/build_windows.yaml
|
||||
secrets: inherit
|
||||
with:
|
||||
sign: true
|
||||
deploy-mode: true
|
||||
arch: ${{ matrix.arch }}
|
||||
version: ${{ needs.prepare.outputs.nightly-version }}
|
||||
|
||||
macos:
|
||||
if: github.event_name != 'workflow_dispatch' || inputs.macos
|
||||
needs: prepare
|
||||
name: macOS
|
||||
uses: ./.github/workflows/build_macos.yaml
|
||||
secrets: inherit
|
||||
with:
|
||||
sign: true
|
||||
deploy-mode: true
|
||||
base-url: https://packages.element.io/${{ needs.prepare.outputs.packages-dir }}
|
||||
version: ${{ needs.prepare.outputs.nightly-version }}
|
||||
|
||||
# We do not put these calls into deploy-mode as we do not want it to add to the packages.element.io artifact
|
||||
# We ship this build via reprepro only
|
||||
linux:
|
||||
if: github.event_name != 'workflow_dispatch' || inputs.linux
|
||||
needs: prepare
|
||||
name: Linux ${{ matrix.arch }} (sqlcipher system)
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
uses: ./.github/workflows/build_linux.yaml
|
||||
with:
|
||||
arch: ${{ matrix.arch }}
|
||||
config: ${{ needs.prepare.outputs.config }}
|
||||
sqlcipher: system
|
||||
version: ${{ needs.prepare.outputs.nightly-version }}
|
||||
|
||||
# We ship the static build via static tarball only
|
||||
linux_static:
|
||||
if: github.event_name != 'workflow_dispatch' || inputs.linux
|
||||
needs: prepare
|
||||
name: Linux (sqlcipher static)
|
||||
uses: ./.github/workflows/build_linux.yaml
|
||||
with:
|
||||
arch: amd64
|
||||
deploy-mode: true
|
||||
config: ${{ needs.prepare.outputs.config }}
|
||||
sqlcipher: static
|
||||
version: ${{ needs.prepare.outputs.nightly-version }}
|
||||
|
||||
# This deploy job only handles Windows, macOS & linux_static as those are stateless and static.
|
||||
# Linux will be deployed via reprepro after it, but we list it as a dependency to abort if it fails.
|
||||
deploy:
|
||||
needs:
|
||||
- prepare
|
||||
- macos
|
||||
- linux
|
||||
- linux_static
|
||||
- windows
|
||||
runs-on: ubuntu-latest
|
||||
name: Deploy
|
||||
if: |
|
||||
(
|
||||
github.event_name != 'workflow_dispatch' &&
|
||||
github.event.release.prerelease != true
|
||||
) || (
|
||||
always() && !failure() && !cancelled() && inputs.deploy &&
|
||||
(inputs.macos || inputs.windows || inputs.linux)
|
||||
)
|
||||
environment: packages.element.io
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: packages.element.io
|
||||
path: packages.element.io
|
||||
|
||||
- name: Deploy artifacts
|
||||
run: |
|
||||
aws s3 cp --recursive packages.element.io/ s3://$R2_BUCKET/$DEPLOYMENT_DIR --endpoint-url $R2_URL --region auto
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_TOKEN }}
|
||||
R2_URL: ${{ vars.CF_R2_S3_API }}
|
||||
DEPLOYMENT_DIR: ${{ needs.prepare.outputs.packages-dir }}
|
||||
|
||||
- name: Notify packages.element.io of new files
|
||||
uses: peter-evans/repository-dispatch@bf47d102fdb849e755b0b0023ea3e81a44b6f570 # v2
|
||||
with:
|
||||
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
repository: vector-im/packages.element.io
|
||||
event-type: packages-index
|
||||
|
||||
reprepro:
|
||||
needs:
|
||||
- linux
|
||||
# We queue this after the other deploy stage as we want to abort if that fails
|
||||
- deploy
|
||||
name: Run reprepro ${{ matrix.arch }}
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [amd64, arm64]
|
||||
if: |
|
||||
(
|
||||
github.event_name != 'workflow_dispatch' &&
|
||||
github.event.release.prerelease != true
|
||||
) || (
|
||||
always() && !failure() && !cancelled() && inputs.deploy && inputs.linux
|
||||
)
|
||||
uses: ./.github/workflows/reprepro.yaml
|
||||
secrets: inherit
|
||||
with:
|
||||
artifact-name: linux-${{ matrix.arch }}-sqlcipher-system
|
||||
164
.github/workflows/build_and_test.yaml
vendored
164
.github/workflows/build_and_test.yaml
vendored
@@ -1,164 +0,0 @@
|
||||
name: Build and Test
|
||||
on:
|
||||
pull_request: {}
|
||||
push:
|
||||
branches: [develop, staging, master]
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
jobs:
|
||||
fetch:
|
||||
uses: ./.github/workflows/build_prepare.yaml
|
||||
with:
|
||||
config: ${{ github.event.pull_request.base.ref == 'develop' && 'element.io/nightly' || 'element.io/release' }}
|
||||
version: ${{ github.event.pull_request.base.ref == 'develop' && 'develop' || '' }}
|
||||
|
||||
windows:
|
||||
needs: fetch
|
||||
name: Windows
|
||||
uses: ./.github/workflows/build_windows.yaml
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x64, x86]
|
||||
with:
|
||||
arch: ${{ matrix.arch }}
|
||||
|
||||
# This allows core contributors to test changes to the dockerbuild image within a pull request
|
||||
linux_docker:
|
||||
name: Linux docker
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'pull_request'
|
||||
outputs:
|
||||
docker-image: ${{ steps.docker.outputs.image }}
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}-dockerbuild-pr
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: "Get modified files"
|
||||
id: changed_files
|
||||
uses: tj-actions/changed-files@41960309398d165631f08c5df47a11147e14712b # v39
|
||||
with:
|
||||
files: |
|
||||
dockerbuild/*
|
||||
- name: Log in to the Container registry
|
||||
if: steps.changed_files.outputs.any_modified == 'true'
|
||||
uses: docker/login-action@b4bedf8053341df3b5a9f9e0f2cf4e79e27360c6
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- id: docker
|
||||
if: steps.changed_files.outputs.any_modified == 'true'
|
||||
run: |
|
||||
echo "image=$IMAGE:$PR" >> $GITHUB_OUTPUT
|
||||
env:
|
||||
IMAGE: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
PR: ${{ github.event.pull_request.number }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
if: steps.changed_files.outputs.any_modified == 'true'
|
||||
uses: docker/build-push-action@4c1b68d83ad20cc1a09620ca477d5bbbb5fa14d0
|
||||
with:
|
||||
context: dockerbuild
|
||||
push: true
|
||||
tags: ${{ steps.docker.outputs.image }}
|
||||
|
||||
linux:
|
||||
needs:
|
||||
- fetch
|
||||
- linux_docker
|
||||
name: "Linux (${{ matrix.arch }}) (sqlcipher: ${{ matrix.sqlcipher }})"
|
||||
uses: ./.github/workflows/build_linux.yaml
|
||||
strategy:
|
||||
matrix:
|
||||
sqlcipher: [system, static]
|
||||
arch: [amd64, arm64]
|
||||
exclude:
|
||||
# FIXME: This combination yields a broken Seshat at this time
|
||||
# Errors at launch with `undefined symbol: PKCS5_PBKDF2_HMAC
|
||||
- arch: arm64
|
||||
sqlcipher: static
|
||||
with:
|
||||
config: ${{ github.event.pull_request.base.ref == 'develop' && 'element.io/nightly' || 'element.io/release' }}
|
||||
sqlcipher: ${{ matrix.sqlcipher }}
|
||||
docker-image: ${{ needs.linux_docker.outputs.docker-image }}
|
||||
arch: ${{ matrix.arch }}
|
||||
|
||||
macos:
|
||||
needs: fetch
|
||||
name: macOS
|
||||
uses: ./.github/workflows/build_macos.yaml
|
||||
|
||||
test:
|
||||
needs:
|
||||
- macos
|
||||
- linux
|
||||
- windows
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- name: macOS Universal
|
||||
os: macos
|
||||
artifact: macos
|
||||
executable: "/Volumes/Element/Element.app/Contents/MacOS/Element"
|
||||
prepare_cmd: "hdiutil attach ./dist/*.dmg -mountpoint /Volumes/Element"
|
||||
- name: "Linux (amd64) (sqlcipher: system)"
|
||||
os: ubuntu
|
||||
artifact: linux-amd64-sqlcipher-system
|
||||
executable: "element-desktop"
|
||||
prepare_cmd: "sudo apt install ./dist/*.deb"
|
||||
- name: "Linux (amd64) (sqlcipher: static)"
|
||||
os: ubuntu
|
||||
artifact: linux-amd64-sqlcipher-static
|
||||
executable: "element-desktop"
|
||||
prepare_cmd: "sudo apt install ./dist/*.deb"
|
||||
- name: Windows (x86)
|
||||
os: windows
|
||||
artifact: win-x86
|
||||
executable: "./dist/win-ia32-unpacked/Element.exe"
|
||||
- name: Windows (x64)
|
||||
os: windows
|
||||
artifact: win-x64
|
||||
executable: "./dist/win-unpacked/Element.exe"
|
||||
name: Test ${{ matrix.name }}
|
||||
runs-on: ${{ matrix.os }}-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: "yarn"
|
||||
|
||||
- name: Install Deps
|
||||
run: "yarn install --frozen-lockfile"
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ${{ matrix.artifact }}
|
||||
path: dist
|
||||
|
||||
- name: Prepare for tests
|
||||
run: ${{ matrix.prepare_cmd }}
|
||||
if: matrix.prepare_cmd
|
||||
|
||||
- name: Run tests
|
||||
uses: coactions/setup-xvfb@b6b4fcfb9f5a895edadc3bc76318fae0ac17c8b3 # v1
|
||||
timeout-minutes: 5
|
||||
with:
|
||||
run: "yarn test"
|
||||
env:
|
||||
ELEMENT_DESKTOP_EXECUTABLE: ${{ matrix.executable }}
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: ${{ matrix.artifact }}
|
||||
path: test_artifacts
|
||||
retention-days: 1
|
||||
190
.github/workflows/build_linux.yaml
vendored
190
.github/workflows/build_linux.yaml
vendored
@@ -1,190 +0,0 @@
|
||||
# This workflow relies on actions/cache to store the hak dependency artifacts as they take a long time to build
|
||||
# Due to this extra care must be taken to only ever run all build_* scripts against the same branch to ensure
|
||||
# the correct cache scoping, and additional care must be taken to not run untrusted actions on the develop branch.
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
arch:
|
||||
type: string
|
||||
required: true
|
||||
description: "The architecture to build for, one of 'amd64' | 'arm64'"
|
||||
config:
|
||||
type: string
|
||||
required: true
|
||||
description: "The config directory to use"
|
||||
version:
|
||||
type: string
|
||||
required: false
|
||||
description: "Version string to override the one in package.json, used for non-release builds"
|
||||
sqlcipher:
|
||||
type: string
|
||||
required: true
|
||||
description: "How to link sqlcipher, one of 'system' | 'static'"
|
||||
deploy-mode:
|
||||
type: boolean
|
||||
required: false
|
||||
description: "Whether to arrange artifacts in the arrangement needed for deployment, skipping unrelated ones"
|
||||
docker-image:
|
||||
type: string
|
||||
required: false
|
||||
description: "The docker image to use for the build, defaults to ghcr.io/vector-im/element-desktop-dockerbuild"
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ${{ inputs.docker-image || format('ghcr.io/vector-im/element-desktop-dockerbuild:{0}', github.ref_name == 'master' && 'master' || 'develop') }}
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
steps:
|
||||
- uses: kanga333/variable-mapper@master
|
||||
id: config
|
||||
with:
|
||||
key: "${{ inputs.arch }}"
|
||||
export_to: output
|
||||
map: |
|
||||
{
|
||||
"amd64": {
|
||||
"target": "x86_64-unknown-linux-gnu",
|
||||
"arch": "x86-64"
|
||||
},
|
||||
"arm64": {
|
||||
"target": "aarch64-unknown-linux-gnu",
|
||||
"arch": "aarch64",
|
||||
"build-args": "--arm64"
|
||||
}
|
||||
}
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: webapp
|
||||
|
||||
- name: Cache .hak
|
||||
id: cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
key: ${{ runner.os }}-${{ inputs.docker-image || github.ref_name }}-${{ inputs.sqlcipher }}-${{ inputs.arch }}-${{ hashFiles('hakHash', 'electronVersion') }}
|
||||
path: |
|
||||
./.hak
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: "yarn"
|
||||
env:
|
||||
# Workaround for https://github.com/actions/setup-node/issues/317
|
||||
FORCE_COLOR: 0
|
||||
|
||||
# Does not need branch matching as only analyses this layer
|
||||
- name: Install Deps
|
||||
run: "yarn install --frozen-lockfile"
|
||||
|
||||
- name: Prepare for static sqlcipher build
|
||||
if: inputs.sqlcipher == 'static'
|
||||
run: |
|
||||
echo "SQLCIPHER_BUNDLED=1" >> $GITHUB_ENV
|
||||
|
||||
# Ideally the docker image would be ready for cross-compilation but libsqlcipher-dev is not Multi-Arch compatible
|
||||
# https://unix.stackexchange.com/a/349359
|
||||
- name: Prepare for cross compilation
|
||||
if: steps.cache.outputs.cache-hit != 'true' && inputs.arch == 'arm64'
|
||||
run: |
|
||||
set -x
|
||||
sed -i 's/deb http/deb [arch=amd64] http/g' /etc/apt/sources.list
|
||||
echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports/ bionic main multiverse restricted universe" | tee -a /etc/apt/sources.list
|
||||
echo "deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports/ bionic-updates main multiverse restricted universe" | tee -a /etc/apt/sources.list
|
||||
dpkg --add-architecture arm64
|
||||
apt-get -qq update
|
||||
apt-get -qq install --no-install-recommends crossbuild-essential-arm64 libsqlcipher-dev:arm64 libssl-dev:arm64 libsecret-1-dev:arm64 libgnome-keyring-dev:arm64
|
||||
rustup target add aarch64-unknown-linux-gnu
|
||||
mv dockerbuild/aarch64/.cargo .
|
||||
cat dockerbuild/aarch64/.env >> $GITHUB_ENV
|
||||
|
||||
- name: Build Natives
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: "yarn build:native --target ${{ steps.config.outputs.target }}"
|
||||
|
||||
- name: "[Nightly] Resolve version"
|
||||
id: nightly
|
||||
if: inputs.version != ''
|
||||
run: |
|
||||
echo "config-args=--nightly '${{ inputs.version }}'" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Generate debian files and arguments
|
||||
id: debian
|
||||
run: |
|
||||
if [ -f changelog.Debian ]; then
|
||||
echo "config-args=--deb-changelog changelog.Debian" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Build App
|
||||
run: |
|
||||
npx ts-node scripts/generate-builder-config.ts \
|
||||
${{ steps.nightly.outputs.config-args }} \
|
||||
${{ steps.debian.outputs.config-args }}
|
||||
yarn build --publish never -l --config electron-builder.json ${{ steps.config.outputs.build-args }}
|
||||
|
||||
- name: Check native libraries
|
||||
run: |
|
||||
set -x
|
||||
shopt -s globstar
|
||||
|
||||
FILES=$(file dist/**/*.node)
|
||||
echo "$FILES"
|
||||
|
||||
if [ grep -v "$ARCH" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
LIBS=$(readelf -d dist/**/*.node | grep NEEDED)
|
||||
echo "$LIBS"
|
||||
|
||||
set +x
|
||||
assert_contains_string() { [[ "$1" == *"$2"* ]]; }
|
||||
! assert_contains_string "$LIBS" "libcrypto.so.1.1"
|
||||
if [ "$SQLCIPHER_BUNDLED" == "1" ]; then
|
||||
! assert_contains_string "$LIBS" "libsqlcipher.so.0"
|
||||
else
|
||||
assert_contains_string "$LIBS" "libsqlcipher.so.0"
|
||||
fi
|
||||
env:
|
||||
ARCH: ${{ steps.config.outputs.arch }}
|
||||
|
||||
- name: Stash deb package
|
||||
if: inputs.deploy-mode
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: linux-sqlcipher-${{ inputs.sqlcipher }}-deb
|
||||
path: dist/*.deb
|
||||
retention-days: 1
|
||||
|
||||
- name: Prepare artifacts for deployment
|
||||
if: inputs.deploy-mode
|
||||
run: |
|
||||
mv dist _dist
|
||||
mkdir -p "dist/install/linux/glibc-x86-64/"
|
||||
mv _dist/*.tar.gz "dist/install/linux/glibc-x86-64"
|
||||
|
||||
# We don't wish to store the tarball for every nightly ever, so we only keep the latest
|
||||
- name: "[Nightly] Strip version from tarball"
|
||||
if: inputs.deploy-mode && inputs.version != ''
|
||||
run: |
|
||||
mv dist/install/linux/glibc-x86-64/*.tar.gz "dist/install/linux/glibc-x86-64/element-desktop-nightly.tar.gz"
|
||||
|
||||
- name: "[Release] Prepare release latest symlink"
|
||||
if: inputs.deploy-mode && inputs.version == ''
|
||||
shell: bash
|
||||
run: |
|
||||
ln -s "$(find . -type f -iname "*.tar.gz" | xargs -0 -n1 -- basename)" "element-desktop.tar.gz"
|
||||
working-directory: "dist/install/linux/glibc-x86-64"
|
||||
|
||||
# We exclude *-unpacked as it loses permissions and the tarball contains it with correct permissions
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ inputs.deploy-mode && 'packages.element.io' || format('linux-{0}-sqlcipher-{1}', inputs.arch, inputs.sqlcipher) }}
|
||||
path: |
|
||||
dist
|
||||
!dist/*-unpacked/**
|
||||
retention-days: 1
|
||||
157
.github/workflows/build_macos.yaml
vendored
157
.github/workflows/build_macos.yaml
vendored
@@ -1,157 +0,0 @@
|
||||
# This workflow relies on actions/cache to store the hak dependency artifacts as they take a long time to build
|
||||
# Due to this extra care must be taken to only ever run all build_* scripts against the same branch to ensure
|
||||
# the correct cache scoping, and additional care must be taken to not run untrusted actions on the develop branch.
|
||||
on:
|
||||
workflow_call:
|
||||
secrets:
|
||||
APPLE_ID:
|
||||
required: false
|
||||
APPLE_ID_PASSWORD:
|
||||
required: false
|
||||
APPLE_TEAM_ID:
|
||||
required: false
|
||||
APPLE_CSC_KEY_PASSWORD:
|
||||
required: false
|
||||
APPLE_CSC_LINK:
|
||||
required: false
|
||||
inputs:
|
||||
version:
|
||||
type: string
|
||||
required: false
|
||||
description: "Version string to override the one in package.json, used for non-release builds"
|
||||
sign:
|
||||
type: string
|
||||
required: false
|
||||
description: "Whether to sign & notarise the build, requires 'packages.element.io' environment"
|
||||
deploy-mode:
|
||||
type: boolean
|
||||
required: false
|
||||
description: "Whether to arrange artifacts in the arrangement needed for deployment, skipping unrelated ones"
|
||||
base-url:
|
||||
type: string
|
||||
required: false
|
||||
description: "The URL to which the output will be deployed, required if deploy-mode is enabled."
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-latest
|
||||
environment: ${{ inputs.sign && 'packages.element.io' || '' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: webapp
|
||||
|
||||
- name: Cache .hak
|
||||
id: cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
key: ${{ runner.os }}-${{ hashFiles('hakHash', 'electronVersion') }}
|
||||
path: |
|
||||
./.hak
|
||||
|
||||
- name: Install Rust
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
rustup toolchain install stable --profile minimal --no-self-update
|
||||
rustup default stable
|
||||
rustup target add aarch64-apple-darwin
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: "yarn"
|
||||
|
||||
# Does not need branch matching as only analyses this layer
|
||||
- name: Install Deps
|
||||
run: "yarn install --frozen-lockfile"
|
||||
|
||||
- name: Build Natives
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: "yarn build:native:universal"
|
||||
|
||||
- name: "[Nightly] Resolve version"
|
||||
id: nightly
|
||||
if: inputs.version != ''
|
||||
run: |
|
||||
echo "config-args=--nightly '${{ inputs.version }}'" >> $GITHUB_OUTPUT
|
||||
|
||||
# We split these because electron-builder gets upset if we set CSC_LINK even to an empty string
|
||||
- name: "[Signed] Build App"
|
||||
if: inputs.sign != ''
|
||||
run: |
|
||||
scripts/generate-builder-config.ts ${{ steps.nightly.outputs.config-args }} --notarytool-team-id='${{ secrets.APPLE_TEAM_ID }}'
|
||||
yarn build:universal --publish never --config electron-builder.json
|
||||
env:
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
|
||||
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CSC_KEY_PASSWORD }}
|
||||
CSC_LINK: ${{ secrets.APPLE_CSC_LINK }}
|
||||
|
||||
- name: Check app was signed & notarised successfully
|
||||
if: inputs.sign != ''
|
||||
run: |
|
||||
hdiutil attach dist/*.dmg
|
||||
codesign -dv --verbose=4 /Volumes/Element*/*.app
|
||||
spctl -a -vvv -t install /Volumes/Element*/*.app
|
||||
hdiutil detach /Volumes/Element*
|
||||
|
||||
- name: "[Unsigned] Build App"
|
||||
if: inputs.sign == ''
|
||||
run: |
|
||||
scripts/generate-builder-config.ts ${{ steps.nightly.outputs.config-args }}
|
||||
yarn build:universal --publish never --config electron-builder.json
|
||||
env:
|
||||
CSC_IDENTITY_AUTO_DISCOVERY: false
|
||||
|
||||
- name: Prepare artifacts for deployment
|
||||
if: inputs.deploy-mode
|
||||
run: |
|
||||
mv dist _dist
|
||||
mkdir -p dist/install/macos dist/update/macos
|
||||
mv _dist/*-mac.zip dist/update/macos/
|
||||
mv _dist/*.dmg dist/install/macos/
|
||||
|
||||
PKG_JSON_VERSION=$(cat package.json | jq -r .version)
|
||||
LATEST=$(find dist -type f -iname "*-mac.zip" | xargs -0 -n1 -- basename)
|
||||
# Encode spaces in the URL as Squirrel.Mac complains about bad JSON otherwise
|
||||
URL="${{ inputs.base-url }}/update/macos/${LATEST// /%20}"
|
||||
|
||||
jq -n --arg version "${VERSION:-$PKG_JSON_VERSION}" --arg url "$URL" '
|
||||
{
|
||||
currentRelease: $version,
|
||||
releases: [{
|
||||
version: $version,
|
||||
updateTo: {
|
||||
version: $version,
|
||||
url: $url,
|
||||
},
|
||||
}],
|
||||
}
|
||||
' > dist/update/macos/releases.json
|
||||
jq -n --arg url "$URL" '
|
||||
{ url: $url }
|
||||
' > dist/update/macos/releases-legacy.json
|
||||
env:
|
||||
VERSION: ${{ inputs.version }}
|
||||
|
||||
# We don't wish to store the installer for every nightly ever, so we only keep the latest
|
||||
- name: "[Nightly] Strip version from installer file"
|
||||
if: inputs.deploy-mode && inputs.version != ''
|
||||
run: |
|
||||
mv dist/install/macos/*.dmg "dist/install/macos/Element Nightly.dmg"
|
||||
|
||||
- name: "[Release] Prepare release latest symlink"
|
||||
if: inputs.deploy-mode && inputs.version == ''
|
||||
run: |
|
||||
ln -s "$(find . -type f -iname "*.dmg" | xargs -0 -n1 -- basename)" "Element.dmg"
|
||||
working-directory: "dist/install/macos"
|
||||
|
||||
# We exclude mac-universal as the unpacked app takes forever to upload and zip and dmg already contain it
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ inputs.deploy-mode && 'packages.element.io' || 'macos' }}
|
||||
path: |
|
||||
dist
|
||||
!dist/mac-universal/**
|
||||
retention-days: 1
|
||||
140
.github/workflows/build_prepare.yaml
vendored
140
.github/workflows/build_prepare.yaml
vendored
@@ -1,140 +0,0 @@
|
||||
# This action helps perform common actions before the build_* actions are started in parallel.
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
config:
|
||||
type: string
|
||||
required: true
|
||||
description: "The config directory to use"
|
||||
version:
|
||||
type: string
|
||||
required: false
|
||||
description: "The version tag to fetch, or 'develop', will pick automatically if not passed"
|
||||
nightly:
|
||||
type: boolean
|
||||
required: false
|
||||
default: false
|
||||
description: "Whether the build is a Nightly and to calculate the version strings new builds should use"
|
||||
secrets:
|
||||
# Required if `nightly` is set
|
||||
CF_R2_ACCESS_KEY_ID:
|
||||
required: false
|
||||
# Required if `nightly` is set
|
||||
CF_R2_TOKEN:
|
||||
required: false
|
||||
outputs:
|
||||
nightly-version:
|
||||
description: "The version string the next Nightly should use, only output for nightly"
|
||||
value: ${{ jobs.prepare.outputs.nightly-version }}
|
||||
packages-dir:
|
||||
description: "The directory non-deb packages for this run should live in within packages.element.io"
|
||||
value: ${{ inputs.nightly && 'nightly' || 'desktop' }}
|
||||
# This is just a simple pass-through of the input to simplify reuse of complex inline conditions
|
||||
config:
|
||||
description: "The relative path to the config file for this run"
|
||||
value: ${{ inputs.config }}
|
||||
jobs:
|
||||
prepare:
|
||||
name: Prepare
|
||||
environment: ${{ inputs.nightly && 'packages.element.io' || '' }}
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
nightly-version: ${{ steps.versions.outputs.nightly }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: "yarn"
|
||||
|
||||
- name: Install Deps
|
||||
run: "yarn install --frozen-lockfile"
|
||||
|
||||
- name: Fetch Element Web
|
||||
run: yarn run fetch --noverify -d ${{ inputs.config }} ${{ inputs.version }}
|
||||
|
||||
# We split this out to save the build_* scripts having to do it to make use of `hashFiles` in the cache action
|
||||
- name: Generate cache hash files
|
||||
run: |
|
||||
yarn run --silent electron --version > electronVersion
|
||||
cat package.json | jq -c .hakDependencies | sha1sum > hakHash
|
||||
find hak -type f -print0 | xargs -0 sha1sum >> hakHash
|
||||
find scripts/hak -type f -print0 | xargs -0 sha1sum >> hakHash
|
||||
|
||||
- name: "[Nightly] Calculate version"
|
||||
id: versions
|
||||
if: inputs.nightly
|
||||
run: |
|
||||
# Find all latest Nightly versions
|
||||
aws s3 cp s3://$R2_BUCKET/nightly/update/macos/releases.json - --endpoint-url $R2_URL --region auto | jq -r .currentRelease >> VERSIONS
|
||||
aws s3 cp s3://$R2_BUCKET/debian/dists/default/main/binary-amd64/Packages - --endpoint-url $R2_URL --region auto | grep "Package: element-nightly" -A 50 | grep Version -m1 | sed -n 's/Version: //p' >> VERSIONS
|
||||
aws s3 cp s3://$R2_BUCKET/debian/dists/default/main/binary-arm64/Packages - --endpoint-url $R2_URL --region auto | grep "Package: element-nightly" -A 50 | grep Version -m1 | sed -n 's/Version: //p' >> VERSIONS
|
||||
aws s3 cp s3://$R2_BUCKET/nightly/update/win32/x64/RELEASES - --endpoint-url $R2_URL --region auto | awk '{print $2}' | cut -d "-" -f 5 | cut -c 8- >> VERSIONS
|
||||
aws s3 cp s3://$R2_BUCKET/nightly/update/win32/ia32/RELEASES - --endpoint-url $R2_URL --region auto | awk '{print $2}' | cut -d "-" -f 5 | cut -c 8- >> VERSIONS
|
||||
|
||||
# Pick the greatest one
|
||||
VERSION=$(cat VERSIONS | sort -uf | tail -n1)
|
||||
# Increment it
|
||||
echo "nightly=$(scripts/generate-nightly-version.ts --latest $VERSION)" >> $GITHUB_OUTPUT
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_TOKEN }}
|
||||
R2_BUCKET: ${{ vars.R2_BUCKET }}
|
||||
R2_URL: ${{ vars.CF_R2_S3_API }}
|
||||
|
||||
- name: Check version
|
||||
id: package
|
||||
run: |
|
||||
echo "version=$(cat package.json | jq -r .version)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: "[Release] Fetch release"
|
||||
id: release
|
||||
if: ${{ !inputs.nightly && inputs.version != 'develop' }}
|
||||
uses: cardinalby/git-get-release-action@cedef2faf69cb7c55b285bad07688d04430b7ada # v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
with:
|
||||
tag: v${{ steps.package.outputs.version }}
|
||||
|
||||
- name: "[Release] Write changelog"
|
||||
if: ${{ !inputs.nightly && inputs.version != 'develop' }}
|
||||
run: |
|
||||
TIME=$(date -d "$PUBLISHED_AT" -R)
|
||||
echo "element-desktop ($VERSION) default; urgency=medium" >> changelog.Debian
|
||||
echo "$BODY" | sed 's/^##/\n */g;s/^\*/ */g' | perl -pe 's/\[.+?]\((.+?)\)/\1/g' >> changelog.Debian
|
||||
echo "" >> changelog.Debian
|
||||
echo " -- $ACTOR <support@element.io> $TIME" >> changelog.Debian
|
||||
env:
|
||||
ACTOR: ${{ github.actor }}
|
||||
VERSION: v${{ steps.package.outputs.version }}
|
||||
BODY: ${{ steps.release.outputs.body }}
|
||||
PUBLISHED_AT: ${{ steps.release.outputs.published_at }}
|
||||
|
||||
- name: "[Nightly] Write summary"
|
||||
if: inputs.nightly
|
||||
run: |
|
||||
BUNDLE_HASH=$(npx asar l webapp.asar | grep /bundles/ | head -n 1 | sed 's|.*/||')
|
||||
WEBAPP_VERSION=$(./scripts/get-version.ts)
|
||||
WEB_VERSION=${WEBAPP_VERSION:0:12}
|
||||
REACT_VERSION=${WEBAPP_VERSION:19:12}
|
||||
JS_VERSION=${WEBAPP_VERSION:35:12}
|
||||
|
||||
echo "### Nightly build ${{ steps.versions.outputs.nightly }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Component | Version |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| ----------- | ------- |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Bundle Hash | $BUNDLE_HASH |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Element Web | [$WEB_VERSION](https://github.com/vector-im/element-web/commit/$WEB_VERSION) |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| React SDK | [$REACT_VERSION](https://github.com/matrix-org/matrix-react-sdk/commit/$REACT_VERSION) |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| JS SDK | [$JS_VERSION](https://github.com/matrix-org/matrix-js-sdk/commit/$JS_VERSION) |" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: webapp
|
||||
retention-days: 1
|
||||
path: |
|
||||
webapp.asar
|
||||
package.json
|
||||
electronVersion
|
||||
hakHash
|
||||
changelog.Debian
|
||||
204
.github/workflows/build_windows.yaml
vendored
204
.github/workflows/build_windows.yaml
vendored
@@ -1,204 +0,0 @@
|
||||
# This workflow relies on actions/cache to store the hak dependency artifacts as they take a long time to build
|
||||
# Due to this extra care must be taken to only ever run all build_* scripts against the same branch to ensure
|
||||
# the correct cache scoping, and additional care must be taken to not run untrusted actions on the develop branch.
|
||||
on:
|
||||
workflow_call:
|
||||
secrets:
|
||||
ESIGNER_USER_NAME:
|
||||
required: false
|
||||
ESIGNER_USER_PASSWORD:
|
||||
required: false
|
||||
ESIGNER_USER_TOTP:
|
||||
required: false
|
||||
inputs:
|
||||
arch:
|
||||
type: string
|
||||
required: true
|
||||
description: "The architecture to build for, one of 'x64' | 'x86' | 'arm64'"
|
||||
version:
|
||||
type: string
|
||||
required: false
|
||||
description: "Version string to override the one in package.json, used for non-release builds"
|
||||
sign:
|
||||
type: string
|
||||
required: false
|
||||
description: "Whether to sign & notarise the build, requires 'packages.element.io' environment"
|
||||
deploy-mode:
|
||||
type: boolean
|
||||
required: false
|
||||
description: "Whether to arrange artifacts in the arrangement needed for deployment, skipping unrelated ones"
|
||||
jobs:
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
environment: ${{ inputs.sign && 'packages.element.io' || '' }}
|
||||
env:
|
||||
SIGNTOOL_PATH: "C:/Program Files (x86)/Windows Kits/10/bin/10.0.22000.0/x86/signtool.exe"
|
||||
steps:
|
||||
- uses: kanga333/variable-mapper@3681b75f5c6c00162721168fb91ab74925eaebcb
|
||||
id: config
|
||||
with:
|
||||
key: "${{ inputs.arch }}"
|
||||
export_to: output
|
||||
map: |
|
||||
{
|
||||
"x64": {
|
||||
"target": "x86_64-pc-windows-msvc",
|
||||
"dir": "x64"
|
||||
},
|
||||
"arm64": {
|
||||
"target": "aarch64-pc-windows-msvc",
|
||||
"build-args": "--arm64",
|
||||
"arch": "amd64_arm64",
|
||||
"dir": "arm64"
|
||||
},
|
||||
"x86": {
|
||||
"target": "i686-pc-windows-msvc",
|
||||
"build-args": "--ia32",
|
||||
"dir": "ia32"
|
||||
}
|
||||
}
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: webapp
|
||||
|
||||
- name: Cache .hak
|
||||
id: cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
key: ${{ runner.os }}-${{ inputs.arch }}-${{ hashFiles('hakHash', 'electronVersion') }}
|
||||
path: |
|
||||
./.hak
|
||||
|
||||
- name: Set up build tools
|
||||
uses: ilammy/msvc-dev-cmd@cec98b9d092141f74527d0afa6feb2af698cfe89
|
||||
with:
|
||||
arch: ${{ steps.config.outputs.arch || inputs.arch }}
|
||||
|
||||
# ActiveTCL package on choco is from 2015,
|
||||
# this one is newer but includes more than we need
|
||||
- name: Choco install tclsh
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
shell: pwsh
|
||||
run: |
|
||||
choco install -y magicsplat-tcl-tk --no-progress
|
||||
echo "${HOME}/AppData/Local/Apps/Tcl86/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||
|
||||
- name: Choco install NetWide Assembler
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
shell: pwsh
|
||||
run: |
|
||||
choco install -y nasm --no-progress
|
||||
echo "C:/Program Files/NASM" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||
|
||||
- name: Install Rust
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
rustup toolchain install stable --profile minimal --no-self-update
|
||||
rustup default stable
|
||||
rustup target add ${{ steps.config.outputs.target }}
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: "yarn"
|
||||
|
||||
# Does not need branch matching as only analyses this layer
|
||||
- name: Install Deps
|
||||
run: "yarn install --frozen-lockfile"
|
||||
|
||||
- name: Build Natives
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
refreshenv
|
||||
yarn build:native --target ${{ steps.config.outputs.target }}
|
||||
|
||||
- name: Install and configure eSigner CKA
|
||||
id: esigner
|
||||
if: inputs.sign
|
||||
run: |
|
||||
Set-StrictMode -Version 'Latest'
|
||||
|
||||
# Download
|
||||
Invoke-WebRequest -OutFile eSigner_CKA.exe "https://packages.element.io/tools/SSL.COM%20eSigner%20CKA_1.0.4-build-20230221_signed.exe"
|
||||
|
||||
# Install
|
||||
New-Item -ItemType Directory -Force -Path "$env:INSTALL_DIR"
|
||||
./eSigner_CKA.exe /CURRENTUSER /VERYSILENT /SUPPRESSMSGBOXES /DIR="${{ env.INSTALL_DIR }}" | Out-Null
|
||||
|
||||
# Disable logger
|
||||
$LogConfig = Get-Content -Path ${{ env.INSTALL_DIR }}/log4net.config
|
||||
$LogConfig[0] = '<log4net threshold="OFF">'
|
||||
$LogConfig | Set-Content -Path ${{ env.INSTALL_DIR }}/log4net.config
|
||||
|
||||
# Configure
|
||||
${{ env.INSTALL_DIR }}/eSignerCKATool.exe config -mode product -user "${{ secrets.ESIGNER_USER_NAME }}" -pass "${{ secrets.ESIGNER_USER_PASSWORD }}" -totp "${{ secrets.ESIGNER_USER_TOTP }}" -key "${{ env.MASTER_KEY_FILE }}" -r
|
||||
${{ env.INSTALL_DIR }}/eSignerCKATool.exe unload
|
||||
${{ env.INSTALL_DIR }}/eSignerCKATool.exe load
|
||||
|
||||
# Find certificate
|
||||
$CodeSigningCert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert | Select-Object -First 1
|
||||
echo Certificate: $CodeSigningCert
|
||||
|
||||
# Extract thumbprint and subject name
|
||||
$Thumbprint = $CodeSigningCert.Thumbprint
|
||||
$SubjectName = ($CodeSigningCert.Subject -replace ", ?", "`n" | ConvertFrom-StringData).CN
|
||||
echo "config-args=--signtool-thumbprint '$Thumbprint' --signtool-subject-name '$SubjectName'" >> $env:GITHUB_OUTPUT
|
||||
env:
|
||||
INSTALL_DIR: C:\Users\runneradmin\eSignerCKA
|
||||
MASTER_KEY_FILE: C:\Users\runneradmin\eSignerCKA\master.key
|
||||
|
||||
- name: "[Nightly] Resolve version"
|
||||
id: nightly
|
||||
if: inputs.version != ''
|
||||
shell: bash
|
||||
run: |
|
||||
echo "config-args=--nightly '${{ inputs.version }}'" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build App
|
||||
run: |
|
||||
yarn ts-node scripts/generate-builder-config.ts ${{ steps.nightly.outputs.config-args }} ${{ steps.esigner.outputs.config-args }}
|
||||
yarn build --publish never -w --config electron-builder.json ${{ steps.config.outputs.build-args }}
|
||||
|
||||
- name: Check app was signed successfully
|
||||
if: inputs.sign != ''
|
||||
run: |
|
||||
. "$env:SIGNTOOL_PATH" verify /pa (get-item ./dist/squirrel-windows*/*.exe)
|
||||
|
||||
- name: Prepare artifacts for deployment
|
||||
if: inputs.deploy-mode
|
||||
shell: bash
|
||||
run: |
|
||||
mv dist _dist
|
||||
mkdir -p "dist/install/win32/$DIR/msi" "dist/update/win32/$DIR"
|
||||
mv _dist/squirrel-windows*/*.exe "dist/install/win32/$DIR"
|
||||
mv _dist/squirrel-windows*/*.nupkg "dist/update/win32/$DIR/"
|
||||
mv _dist/squirrel-windows*/RELEASES "dist/update/win32/$DIR/"
|
||||
# mv _dist/*.msi "dist/install/win32/$DIR/msi/"
|
||||
env:
|
||||
DIR: ${{ steps.config.outputs.dir }}
|
||||
|
||||
# We don't wish to store the installer for every nightly ever, so we only keep the latest
|
||||
- name: "[Nightly] Strip version from installer file"
|
||||
if: inputs.deploy-mode && inputs.version != ''
|
||||
shell: bash
|
||||
run: |
|
||||
mv dist/install/win32/$DIR/*.exe "dist/install/win32/$DIR/Element Nightly Setup.exe"
|
||||
# mv dist/install/win32/$DIR/msi/*.msi "dist/install/win32/$DIR/msi/Element Nightly Setup.msi"
|
||||
env:
|
||||
DIR: ${{ steps.config.outputs.dir }}
|
||||
|
||||
- name: "[Release] Prepare release latest symlink"
|
||||
if: inputs.deploy-mode && inputs.version == ''
|
||||
shell: bash
|
||||
run: |
|
||||
ln -s "$(find . -type f -iname "*.exe" | xargs -0 -n1 -- basename)" "Element Setup.exe"
|
||||
working-directory: "dist/install/win32/${{ steps.config.outputs.dir }}"
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ inputs.deploy-mode && 'packages.element.io' || format('win-{0}', inputs.arch) }}
|
||||
path: dist
|
||||
retention-days: 1
|
||||
43
.github/workflows/dockerbuild.yaml
vendored
43
.github/workflows/dockerbuild.yaml
vendored
@@ -1,43 +0,0 @@
|
||||
name: Dockerbuild
|
||||
on:
|
||||
workflow_dispatch: {}
|
||||
push:
|
||||
branches: [master, develop]
|
||||
paths:
|
||||
- "dockerbuild/**"
|
||||
concurrency: ${{ github.workflow }}-${{ github.ref_name }}
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}-dockerbuild
|
||||
jobs:
|
||||
build:
|
||||
name: Docker Build
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Log in to the Container registry
|
||||
uses: docker/login-action@b4bedf8053341df3b5a9f9e0f2cf4e79e27360c6
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract metadata for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@879dcbb708d40f8b8679d4f7941b938a086e23a7
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@4c1b68d83ad20cc1a09620ca477d5bbbb5fa14d0
|
||||
with:
|
||||
context: dockerbuild
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
8
.github/workflows/localazy_download.yaml
vendored
8
.github/workflows/localazy_download.yaml
vendored
@@ -1,8 +0,0 @@
|
||||
name: Localazy Download
|
||||
on:
|
||||
workflow_dispatch: {}
|
||||
jobs:
|
||||
download:
|
||||
uses: matrix-org/matrix-web-i18n/.github/workflows/localazy_download.yaml@main
|
||||
secrets:
|
||||
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
11
.github/workflows/localazy_upload.yaml
vendored
11
.github/workflows/localazy_upload.yaml
vendored
@@ -1,11 +0,0 @@
|
||||
name: Localazy Upload
|
||||
on:
|
||||
push:
|
||||
branches: [develop]
|
||||
paths:
|
||||
- "src/strings/i18n/en_EN.json"
|
||||
jobs:
|
||||
upload:
|
||||
uses: matrix-org/matrix-web-i18n/.github/workflows/localazy_upload.yaml@main
|
||||
secrets:
|
||||
LOCALAZY_WRITE_KEY: ${{ secrets.LOCALAZY_WRITE_KEY }}
|
||||
12
.github/workflows/preview_changelog.yaml
vendored
Normal file
12
.github/workflows/preview_changelog.yaml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
name: Preview Changelog
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [ opened, edited, labeled ]
|
||||
jobs:
|
||||
changelog:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Preview Changelog
|
||||
uses: matrix-org/allchange@main
|
||||
with:
|
||||
ghToken: ${{ secrets.GITHUB_TOKEN }}
|
||||
9
.github/workflows/pull_request.yaml
vendored
9
.github/workflows/pull_request.yaml
vendored
@@ -1,9 +0,0 @@
|
||||
name: Pull Request
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, edited, labeled, unlabeled, synchronize]
|
||||
jobs:
|
||||
action:
|
||||
uses: matrix-org/matrix-js-sdk/.github/workflows/pull_request.yaml@develop
|
||||
secrets:
|
||||
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
49
.github/workflows/reprepro.yaml
vendored
49
.github/workflows/reprepro.yaml
vendored
@@ -1,49 +0,0 @@
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
artifact-name:
|
||||
type: string
|
||||
required: true
|
||||
description: "The name of the artifact containing the deb to include"
|
||||
secrets:
|
||||
ELEMENT_BOT_TOKEN:
|
||||
required: true
|
||||
CF_R2_ACCESS_KEY_ID:
|
||||
required: true
|
||||
CF_R2_TOKEN:
|
||||
required: true
|
||||
# Protect reprepro database using concurrency
|
||||
concurrency: reprepro
|
||||
jobs:
|
||||
reprepro:
|
||||
name: Deploy debian package
|
||||
environment: packages.element.io
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
R2_INCOMING_BUCKET: ${{ vars.R2_INCOMING_BUCKET }}
|
||||
R2_URL: ${{ vars.CF_R2_S3_API }}
|
||||
steps:
|
||||
- name: Download artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ${{ inputs.artifact-name }}
|
||||
path: dist
|
||||
|
||||
- name: Upload incoming deb
|
||||
id: upload
|
||||
run: |
|
||||
deb="$(ls *.deb | tail -n1)"
|
||||
echo "incoming=$deb" >> $GITHUB_OUTPUT
|
||||
aws s3 cp "$deb" "s3://$R2_INCOMING_BUCKET" --endpoint-url "$R2_URL" --region auto
|
||||
working-directory: dist
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_TOKEN }}
|
||||
|
||||
- name: Notify packages.element.io of incoming deb
|
||||
uses: peter-evans/repository-dispatch@bf47d102fdb849e755b0b0023ea3e81a44b6f570 # v2
|
||||
with:
|
||||
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
repository: vector-im/packages.element.io
|
||||
event-type: reprepro-incoming
|
||||
client-payload: '{"incoming": "${{ steps.upload.outputs.incoming }}"}'
|
||||
43
.github/workflows/static_analysis.yaml
vendored
43
.github/workflows/static_analysis.yaml
vendored
@@ -1,43 +0,0 @@
|
||||
name: Static Analysis
|
||||
on:
|
||||
pull_request: {}
|
||||
push:
|
||||
branches: [develop, master]
|
||||
jobs:
|
||||
ts_lint:
|
||||
name: "Typescript Syntax Check"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: "yarn"
|
||||
|
||||
# Does not need branch matching as only analyses this layer
|
||||
- name: Install Deps
|
||||
run: "yarn install --frozen-lockfile"
|
||||
|
||||
- name: Typecheck
|
||||
run: "yarn run lint:types"
|
||||
|
||||
i18n_lint:
|
||||
name: "i18n Check"
|
||||
uses: matrix-org/matrix-web-i18n/.github/workflows/i18n_check.yml@main
|
||||
|
||||
js_lint:
|
||||
name: "ESLint"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: "yarn"
|
||||
|
||||
# Does not need branch matching as only analyses this layer
|
||||
- name: Install Deps
|
||||
run: "yarn install --frozen-lockfile"
|
||||
|
||||
- name: Run Linter
|
||||
run: "yarn run lint:js"
|
||||
8
.github/workflows/upgrade_dependencies.yml
vendored
8
.github/workflows/upgrade_dependencies.yml
vendored
@@ -1,8 +0,0 @@
|
||||
name: Upgrade Dependencies
|
||||
on:
|
||||
workflow_dispatch: {}
|
||||
jobs:
|
||||
upgrade:
|
||||
uses: matrix-org/matrix-js-sdk/.github/workflows/upgrade_dependencies.yml@develop
|
||||
secrets:
|
||||
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -4,7 +4,8 @@
|
||||
/webapp.asar
|
||||
/packages
|
||||
/deploys
|
||||
node_modules/
|
||||
/node_modules
|
||||
/docker_node_modules
|
||||
/pkg/control
|
||||
/.hak
|
||||
/.yarnrc
|
||||
@@ -12,8 +13,3 @@ node_modules/
|
||||
/.npmrc
|
||||
.vscode
|
||||
.vscode/
|
||||
/test_artifacts/
|
||||
/coverage/
|
||||
yarn-error.log
|
||||
/hak/**/*.js
|
||||
/scripts/hak/**/*.js
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
/build/
|
||||
/dockerbuild/
|
||||
/lib/
|
||||
/node_modules/
|
||||
/packages.elememt.io/
|
||||
/webapp
|
||||
/src/i18n/strings
|
||||
/CHANGELOG.md
|
||||
/package-lock.json
|
||||
/yarn.lock
|
||||
|
||||
**/.idea
|
||||
.vscode
|
||||
.vscode/
|
||||
.tmp
|
||||
.env
|
||||
/coverage
|
||||
/.npmrc
|
||||
/*.log
|
||||
@@ -1 +0,0 @@
|
||||
module.exports = require("eslint-plugin-matrix-org/.prettierrc.js");
|
||||
2385
CHANGELOG.md
2385
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
156
README.md
156
README.md
@@ -1,24 +1,18 @@
|
||||

|
||||

|
||||
[](https://localazy.com/p/element-web)
|
||||
[](https://sonarcloud.io/summary/new_code?id=element-desktop)
|
||||
[](https://sonarcloud.io/summary/new_code?id=element-desktop)
|
||||
[](https://sonarcloud.io/summary/new_code?id=element-desktop)
|
||||
|
||||
# Element Desktop
|
||||
Element Desktop
|
||||
===============
|
||||
|
||||
Element Desktop is a Matrix client for desktop platforms with Element Web at its core.
|
||||
|
||||
# First Steps
|
||||
|
||||
First Steps
|
||||
===========
|
||||
Before you do anything else, fetch the dependencies:
|
||||
|
||||
```
|
||||
yarn install
|
||||
```
|
||||
|
||||
# Fetching Element
|
||||
|
||||
Fetching Element
|
||||
================
|
||||
Since this package is just the Electron wrapper for Element Web, it doesn't contain any of the Element Web code,
|
||||
so the first step is to get a working copy of Element Web. There are a few ways of doing this:
|
||||
|
||||
@@ -30,7 +24,6 @@ yarn run fetch --noverify --cfgdir ""
|
||||
```
|
||||
|
||||
...or if you'd like to use GPG to verify the downloaded package:
|
||||
|
||||
```
|
||||
# Fetch the Element public key from the element.io web server over a secure connection and import
|
||||
# it into your local GPG keychain (you'll need GPG installed). You only need to to do this
|
||||
@@ -41,7 +34,6 @@ yarn run fetch --cfgdir ""
|
||||
```
|
||||
|
||||
...or either of the above, but fetching a specific version of Element:
|
||||
|
||||
```
|
||||
# Fetch the prebuilt release Element package from the element-web GitHub releases page. The version
|
||||
# fetched will be the same as the local element-desktop package.
|
||||
@@ -50,7 +42,6 @@ yarn run fetch --noverify --cfgdir "" v1.5.6
|
||||
|
||||
If you only want to run the app locally and don't need to build packages, you can
|
||||
provide the `webapp` directory directly:
|
||||
|
||||
```
|
||||
# Assuming you've checked out and built a copy of element-web in ../element-web
|
||||
ln -s ../element-web/webapp ./
|
||||
@@ -58,32 +49,42 @@ ln -s ../element-web/webapp ./
|
||||
|
||||
[TODO: add support for fetching develop builds, arbitrary URLs and arbitrary paths]
|
||||
|
||||
# Building
|
||||
|
||||
## Native Build
|
||||
Building
|
||||
========
|
||||
Now you have a copy of Element, you're ready to build packages. If you'd just like to
|
||||
run Element locally, skip to the next section.
|
||||
|
||||
TODO: List native pre-requisites
|
||||
If you'd like to build the native modules (for searching in encrypted rooms and
|
||||
secure storage), do this first. This will take 10 minutes or so, and will
|
||||
require a number of native tools to be installed, depending on your OS (eg.
|
||||
rust, tcl, make/nmake).
|
||||
|
||||
Optionally, [build the native modules](https://github.com/vector-im/element-desktop/blob/develop/docs/native-node-modules.md),
|
||||
which include support for searching in encrypted rooms and secure storage. Skipping this step is fine, you just won't have those features.
|
||||
You'll also to need to make sure you've built the native modules for the same
|
||||
architecture as your package, so for anything more advanced than just building
|
||||
the modules and app for the host architecture see 'Other Architectures'.
|
||||
|
||||
Then, run
|
||||
If you don't need these features, you can skip this step.
|
||||
|
||||
To just build these for your native architecture:
|
||||
```
|
||||
yarn run build:native
|
||||
```
|
||||
|
||||
Now you can build the package:
|
||||
|
||||
```
|
||||
yarn run build
|
||||
```
|
||||
|
||||
This will do a couple of things:
|
||||
* Run the `setversion` script to set the local package version to match whatever
|
||||
version of Element you installed above.
|
||||
* Run electron-builder to build a package. The package built will match the operating system
|
||||
you're running the build process on.
|
||||
|
||||
- Run the `setversion` script to set the local package version to match whatever
|
||||
version of Element you installed above.
|
||||
- Run electron-builder to build a package. The package built will match the operating system
|
||||
you're running the build process on.
|
||||
|
||||
## Docker
|
||||
|
||||
Alternatively, you can also build using docker, which will always produce the linux package:
|
||||
This build step will not build any native modules.
|
||||
|
||||
You can also build using docker, which will always produce the linux package:
|
||||
```
|
||||
# Run this once to make the docker image
|
||||
yarn run docker:setup
|
||||
@@ -96,10 +97,9 @@ yarn run docker:build
|
||||
|
||||
After running, the packages should be in `dist/`.
|
||||
|
||||
# Starting
|
||||
|
||||
Starting
|
||||
========
|
||||
If you'd just like to run the electron app locally for development:
|
||||
|
||||
```
|
||||
# Install electron - we don't normally need electron itself as it's provided
|
||||
# by electron-builder when building packages
|
||||
@@ -107,22 +107,85 @@ yarn add electron
|
||||
yarn start
|
||||
```
|
||||
|
||||
# Config
|
||||
Other Architectures
|
||||
===================
|
||||
Building the native modules will build for the host architecture (and only the
|
||||
host architecture) by default. On Windows, this will automatically determine
|
||||
the architecture to build for based on the environment. Make sure that you have
|
||||
all the [tools required to perform the native modules build](docs/windows-requirements.md)
|
||||
|
||||
|
||||
On macOS, you can build universal native modules too:
|
||||
```
|
||||
yarn run build:native:universal
|
||||
```
|
||||
|
||||
...or you can build for a specific architecture:
|
||||
```
|
||||
yarn run build:native --target x86_64-apple-darwin
|
||||
```
|
||||
or
|
||||
```
|
||||
yarn run build:native --target aarch64-apple-darwin
|
||||
```
|
||||
|
||||
You'll then need to create a built bundle with the same architecture.
|
||||
To bundle a universal build for macOS, run:
|
||||
|
||||
```
|
||||
yarn run build:universal
|
||||
```
|
||||
|
||||
If you're on Windows, you can choose to build specifically for 32 or 64 bit:
|
||||
```
|
||||
yarn run build:32
|
||||
```
|
||||
or
|
||||
```
|
||||
yarn run build:64
|
||||
```
|
||||
|
||||
Note that the native module build system keeps the different architectures
|
||||
separate, so you can keep native modules for several architectures at the same
|
||||
time and switch which are active using a `yarn run hak copy` command, passing
|
||||
the appropriate architectures. This will error if you haven't yet built those
|
||||
architectures. eg:
|
||||
|
||||
```
|
||||
yarn run build:native --target x86_64-apple-darwin
|
||||
# We've now built & linked into place native modules for Intel
|
||||
yarn run build:native --target aarch64-apple-darwin
|
||||
# We've now built Apple Silicon modules too, and linked them into place as the active ones
|
||||
|
||||
yarn run hak copy --target x86_64-apple-darwin
|
||||
# We've now switched back to our Intel modules
|
||||
yarn run hak copy --target x86_64-apple-darwin --target aarch64-apple-darwin
|
||||
# Now our native modules are universal x86_64+aarch64 binaries
|
||||
```
|
||||
|
||||
The current set of native modules are stored in `.hak/hakModules`,
|
||||
so you can use this to check what architecture is currently in place, eg:
|
||||
|
||||
```
|
||||
$ lipo -info .hak/hakModules/keytar/build/Release/keytar.node
|
||||
Architectures in the fat file: .hak/hakModules/keytar/build/Release/keytar.node are: x86_64 arm64
|
||||
```
|
||||
|
||||
Config
|
||||
======
|
||||
If you'd like the packaged Element to have a configuration file, you can create a
|
||||
config directory and place `config.json` in there, then specify this directory
|
||||
with the `--cfgdir` option to `yarn run fetch`, eg:
|
||||
|
||||
```
|
||||
mkdir myconfig
|
||||
cp /path/to/my/config.json myconfig/
|
||||
yarn run fetch --cfgdir myconfig
|
||||
```
|
||||
|
||||
The config dir for the official Element app is in `element.io`. If you use this,
|
||||
your app will auto-update itself using builds from element.io.
|
||||
|
||||
# Profiles
|
||||
Profiles
|
||||
========
|
||||
|
||||
To run multiple instances of the desktop app for different accounts, you can
|
||||
launch the executable with the `--profile` argument followed by a unique
|
||||
@@ -132,25 +195,30 @@ not interfere with the default one.
|
||||
Alternatively, a custom location for the profile data can be specified using the
|
||||
`--profile-dir` flag followed by the desired path.
|
||||
|
||||
# User-specified config.json
|
||||
User-specified config.json
|
||||
==========================
|
||||
|
||||
- `%APPDATA%\$NAME\config.json` on Windows
|
||||
- `$XDG_CONFIG_HOME/$NAME/config.json` or `~/.config/$NAME/config.json` on Linux
|
||||
- `~/Library/Application Support/$NAME/config.json` on macOS
|
||||
+ `%APPDATA%\$NAME\config.json` on Windows
|
||||
+ `$XDG_CONFIG_HOME\$NAME\config.json` or `~/.config/$NAME/config.json` on Linux
|
||||
+ `~/Library/Application Support/$NAME/config.json` on macOS
|
||||
|
||||
In the paths above, `$NAME` is typically `Element`, unless you use `--profile
|
||||
$PROFILE` in which case it becomes `Element-$PROFILE`, or it is using one of
|
||||
the above created by a pre-1.7 install, in which case it will be `Riot` or
|
||||
`Riot-$PROFILE`.
|
||||
|
||||
# Translations
|
||||
Translations
|
||||
==========================
|
||||
|
||||
To add a new translation, head to the [translating doc](https://github.com/vector-im/element-web/blob/develop/docs/translating.md).
|
||||
|
||||
For a developer guide, see the [translating dev doc](https://github.com/vector-im/element-web/blob/develop/docs/translating-dev.md).
|
||||
|
||||
# Report bugs & give feedback
|
||||
[<img src="https://translate.element.io/widgets/element-desktop/-/multi-auto.svg" alt="translationsstatus" width="340">](https://translate.element.io/engage/element-desktop/?utm_source=widget)
|
||||
|
||||
Report bugs & give feedback
|
||||
==========================
|
||||
|
||||
If you run into any bugs or have feedback you'd like to share, please let us know on GitHub.
|
||||
|
||||
To help avoid duplicate issues, please [view existing issues](https://github.com/vector-im/element-web/issues?q=is%3Aopen+is%3Aissue+sort%3Areactions-%2B1-desc) first (and add a +1) or [create a new issue](https://github.com/vector-im/element-web/issues/new/choose) if you can't find it. Please note that this issue tracker is associated with the [element-web](https://github.com/vector-im/element-web) repo, but is also applied to the code in this repo as well.
|
||||
To help avoid duplicate issues, please [view existing issues](https://github.com/vector-im/element-web/issues?q=is%3Aopen+is%3Aissue+sort%3Areactions-%2B1-desc) first (and add a +1) or [create a new issue](https://github.com/vector-im/element-web/issues/new/choose) if you can't find it. Please note that this issue tracker is associated with the [element-web](https://github.com/vector-im/element-web) repo, but is also applied to the code in this repo as well.
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
module.exports = {
|
||||
presets: [["@babel/preset-env", { targets: { node: "current" } }], "@babel/preset-typescript"],
|
||||
};
|
||||
51
build/rebrand_stub/rebrand_stub.c
Normal file
51
build/rebrand_stub/rebrand_stub.c
Normal file
@@ -0,0 +1,51 @@
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <tchar.h>
|
||||
|
||||
/*
|
||||
* This just runs 'Element.exe' with the same args as
|
||||
* this process was invoked with. This gets around the fact that
|
||||
* squirrel always tries to run an executable with the same name,
|
||||
* so fails to restart if the app's name has changed.
|
||||
*/
|
||||
void _tmain( int argc, TCHAR *argv[] )
|
||||
{
|
||||
LPSTR myCmdLine = GetCommandLineA();
|
||||
char cmdLine[32767];
|
||||
|
||||
LPSTR cmdLinePos = cmdLine;
|
||||
LPSTR toRun = "\"Element.exe\" ";
|
||||
strncpy(cmdLinePos, toRun, strlen(toRun));
|
||||
cmdLinePos += strlen(toRun);
|
||||
|
||||
if (myCmdLine[0] == '"') ++myCmdLine;
|
||||
myCmdLine += strlen(argv[0]);
|
||||
if (myCmdLine[0] == '"') ++myCmdLine;
|
||||
if (myCmdLine[0] == ' ') ++myCmdLine;
|
||||
|
||||
strncpy(cmdLinePos, myCmdLine, (cmdLine + 32767) - cmdLinePos);
|
||||
|
||||
STARTUPINFO si;
|
||||
PROCESS_INFORMATION pi;
|
||||
|
||||
ZeroMemory(&si, sizeof(si));
|
||||
si.cb = sizeof(si);
|
||||
ZeroMemory(&pi, sizeof(pi));
|
||||
|
||||
if (!CreateProcess(NULL,
|
||||
cmdLine, // Command line
|
||||
NULL, // Process handle not inheritable
|
||||
NULL, // Thread handle not inheritable
|
||||
FALSE, // Set handle inheritance to FALSE
|
||||
0, // No creation flags
|
||||
NULL, // Use parent's environment block
|
||||
NULL, // Use parent's starting directory
|
||||
&si, // Pointer to STARTUPINFO structure
|
||||
&pi ) // Pointer to PROCESS_INFORMATION structure
|
||||
)
|
||||
{
|
||||
printf("CreateProcess failed (%d).\n", GetLastError());
|
||||
return;
|
||||
}
|
||||
}
|
||||
BIN
build/rebrand_stub/rebrand_stub.exe
Normal file
BIN
build/rebrand_stub/rebrand_stub.exe
Normal file
Binary file not shown.
@@ -1,23 +1,19 @@
|
||||
# Docker image to facilitate building Element Desktop with native bits using a glibc version with broader compatibility
|
||||
FROM buildpack-deps:bionic-curl
|
||||
FROM buildpack-deps:xenial-curl
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
|
||||
RUN curl --proto "=https" -L https://yarnpkg.com/latest.tar.gz | tar xvz && mv yarn-* /yarn && ln -s /yarn/bin/yarn /usr/bin/yarn
|
||||
RUN curl -L https://yarnpkg.com/latest.tar.gz | tar xvz && mv yarn-* /yarn && ln -s /yarn/bin/yarn /usr/bin/yarn
|
||||
RUN apt-get -qq update && apt-get -qq dist-upgrade && \
|
||||
# add repo for git-lfs
|
||||
curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash && \
|
||||
# git ssh for using as docker image on CircleCI
|
||||
# python for node-gyp
|
||||
# rpm is required for FPM to build rpm package
|
||||
# tclsh is required for building SQLite as part of SQLCipher
|
||||
# libsecret-1-dev and libgnome-keyring-dev are required even for prebuild keytar
|
||||
apt-get -qq install --no-install-recommends qtbase5-dev bsdtar build-essential autoconf libssl-dev gcc-multilib g++-multilib lzip rpm python libcurl4 git git-lfs ssh unzip tcl \
|
||||
apt-get -qq install --no-install-recommends qtbase5-dev bsdtar build-essential autoconf libssl-dev gcc-multilib g++-multilib lzip rpm python libcurl3 git git-lfs ssh unzip \
|
||||
libsecret-1-dev libgnome-keyring-dev \
|
||||
libopenjp2-tools \
|
||||
# Used by github actions \
|
||||
jq grep file \
|
||||
# Used by seshat (when not SQLCIPHER_STATIC) \
|
||||
# Used by Seshat
|
||||
libsqlcipher-dev && \
|
||||
# git-lfs
|
||||
git lfs install && \
|
||||
@@ -34,10 +30,10 @@ ENV LC_ALL C.UTF-8
|
||||
|
||||
ENV DEBUG_COLORS true
|
||||
ENV FORCE_COLOR true
|
||||
ENV NODE_VERSION 16.18.1
|
||||
ENV NODE_VERSION 14.17.0
|
||||
|
||||
# this package is used for snapcraft and we should not clear apt list - to avoid apt-get update during snap build
|
||||
RUN curl --proto "=https" -L https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.gz | tar xz -C /usr/local --strip-components=1 && \
|
||||
RUN curl -L https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.gz | tar xz -C /usr/local --strip-components=1 && \
|
||||
unlink /usr/local/CHANGELOG.md && unlink /usr/local/LICENSE && unlink /usr/local/README.md && \
|
||||
# https://github.com/npm/npm/issues/4531
|
||||
npm config set unsafe-perm true
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
[target.aarch64-unknown-linux-gnu]
|
||||
linker = "aarch64-linux-gnu-gcc"
|
||||
rustflags = ["-L/usr/lib/aarch64-linux-gnu"]
|
||||
@@ -1,11 +0,0 @@
|
||||
AS=/usr/bin/aarch64-linux-gnu-as
|
||||
STRIP=/usr/bin/aarch64-linux-gnu-strip
|
||||
AR=/usr/bin/aarch64-linux-gnu-ar
|
||||
CC=/usr/bin/aarch64-linux-gnu-gcc
|
||||
CPP=/usr/bin/aarch64-linux-gnu-cpp
|
||||
CXX=/usr/bin/aarch64-linux-gnu-g++
|
||||
LD=/usr/bin/aarch64-linux-gnu-ld
|
||||
FC=/usr/bin/aarch64-linux-gnu-gfortran
|
||||
PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig
|
||||
CFLAGS=-L/usr/lib/aarch64-linux-gnu
|
||||
RUSTFLAGS=-L/usr/lib/aarch64-linux-gnu
|
||||
@@ -10,27 +10,20 @@ modules from source to ensure we can trust the compiled output. In the future,
|
||||
we may offer a pre-compiled path for those who want to use these features in a
|
||||
custom build of Element without installing the various build tools required.
|
||||
|
||||
Do note that compiling a module for a particular operating system
|
||||
(Linux/macOS/Windows) will need to be done on that operating system.
|
||||
Cross-compiling from a host OS for a different target OS may be possible, but
|
||||
we don't support this flow with Element dependencies at this time.
|
||||
|
||||
The process is automated by [vector-im/element-builder](https://github.com/vector-im/element-builder)
|
||||
when releasing.
|
||||
|
||||
## Building
|
||||
|
||||
Install the pre-requisites for your system:
|
||||
|
||||
- [Windows pre-requisites](https://github.com/vector-im/element-desktop/blob/develop/docs/windows-requirements.md)
|
||||
- Linux: TODO
|
||||
- OS X: TODO
|
||||
|
||||
Then optionally, [add seshat and dependencies to support search in E2E rooms](#adding-seshat-for-search-in-e2e-encrypted-rooms).
|
||||
|
||||
Then, to build for an architecture selected automatically based on your system (recommended), run:
|
||||
when releasing.
|
||||
The following sections explain the manual steps you can use with a custom build of Element to enable
|
||||
these features if you'd like to try them out.
|
||||
It is possible to [build those native modules locally automatically](https://github.com/vector-im/element-desktop#building).
|
||||
|
||||
```
|
||||
yarn run build:native
|
||||
```
|
||||
|
||||
If you need to build for a specific architecture, see [here](#compiling-for-specific-architectures).
|
||||
|
||||
## Adding Seshat for search in E2E encrypted rooms
|
||||
|
||||
Seshat is a native Node module that adds support for local event indexing and
|
||||
@@ -48,7 +41,7 @@ using yarn at the root of this project:
|
||||
|
||||
yarn add matrix-seshat
|
||||
|
||||
You will have to rebuild the native libraries against electron's version
|
||||
You will have to rebuild the native libraries against electron's version of
|
||||
of node rather than your system node, using the `electron-build-env` tool.
|
||||
This is also needed to when pulling in changes to Seshat using `yarn link`.
|
||||
|
||||
@@ -66,92 +59,3 @@ After this is done the Electron version of Element can be run from the main fold
|
||||
as usual using:
|
||||
|
||||
yarn start
|
||||
|
||||
### Statically linking libsqlcipher
|
||||
|
||||
On Windows & macOS we always statically link libsqlcipher for it is not generally available.
|
||||
On Linux by default we will use a system package, on debian & ubuntu this is `libsqlcipher0`,
|
||||
but this is problematic for some other packages, and we found that it may crashes for unknown reasons.
|
||||
By including `SQLCIPHER_BUNDLED=1` in the build environment, the build scripts will fully statically
|
||||
link sqlcipher, including a static build of OpenSSL.
|
||||
|
||||
More info can be found at https://github.com/matrix-org/seshat/issues/102
|
||||
and https://github.com/vector-im/element-web/issues/20926.
|
||||
|
||||
## Compiling for specific architectures
|
||||
|
||||
### macOS
|
||||
|
||||
On macOS, you can build universal native modules too:
|
||||
|
||||
```
|
||||
yarn run build:native:universal
|
||||
```
|
||||
|
||||
...or you can build for a specific architecture:
|
||||
|
||||
```
|
||||
yarn run build:native --target x86_64-apple-darwin
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
yarn run build:native --target aarch64-apple-darwin
|
||||
```
|
||||
|
||||
You'll then need to create a built bundle with the same architecture.
|
||||
To bundle a universal build for macOS, run:
|
||||
|
||||
```
|
||||
yarn run build:universal
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
If you're on Windows, you can choose to build specifically for 32 or 64 bit:
|
||||
|
||||
```
|
||||
yarn run build:32
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
yarn run build:64
|
||||
```
|
||||
|
||||
### Cross compiling
|
||||
|
||||
Compiling a module for a particular operating system (Linux/macOS/Windows) needs
|
||||
to be done on that operating system. Cross-compiling from a host OS for a different
|
||||
target OS may be possible, but we don't support this flow with Element dependencies
|
||||
at this time.
|
||||
|
||||
### Switching between architectures
|
||||
|
||||
The native module build system keeps the different architectures
|
||||
separate, so you can keep native modules for several architectures at the same
|
||||
time and switch which are active using a `yarn run hak copy` command, passing
|
||||
the appropriate architectures. This will error if you haven't yet built those
|
||||
architectures. eg:
|
||||
|
||||
```
|
||||
yarn run build:native --target x86_64-apple-darwin
|
||||
# We've now built & linked into place native modules for Intel
|
||||
yarn run build:native --target aarch64-apple-darwin
|
||||
# We've now built Apple Silicon modules too, and linked them into place as the active ones
|
||||
|
||||
yarn run hak copy --target x86_64-apple-darwin
|
||||
# We've now switched back to our Intel modules
|
||||
yarn run hak copy --target x86_64-apple-darwin --target aarch64-apple-darwin
|
||||
# Now our native modules are universal x86_64+aarch64 binaries
|
||||
```
|
||||
|
||||
The current set of native modules are stored in `.hak/hakModules`,
|
||||
so you can use this to check what architecture is currently in place, eg:
|
||||
|
||||
```
|
||||
$ lipo -info .hak/hakModules/keytar/build/Release/keytar.node
|
||||
Architectures in the fat file: .hak/hakModules/keytar/build/Release/keytar.node are: x86_64 arm64
|
||||
```
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
The Desktop app is capable of self-updating on macOS and Windows.
|
||||
The update server base url is configurable as `update_base_url` in config.json and can be served by a static file host,
|
||||
CDN or object storage.
|
||||
|
||||
Currently all packaging & deployment is handled by [Github actions](https://github.com/vector-im/element-desktop/blob/develop/.github/workflows/build_and_deploy.yaml)
|
||||
|
||||
# Windows
|
||||
|
||||
On Windows the update mechanism used is [Squirrel.Windows](https://github.com/Squirrel/Squirrel.Windows)
|
||||
and can be served by any compatible Squirrel server, such as https://github.com/Tiliq/squirrel-server
|
||||
|
||||
# macOS
|
||||
|
||||
On macOS the update mechanism used is [Squirrel.Mac](https://github.com/Squirrel/Squirrel.Mac)
|
||||
using the newer JSON format as documented [here](https://github.com/Squirrel/Squirrel.Mac#update-file-json-format).
|
||||
@@ -1,39 +1,26 @@
|
||||
# Windows
|
||||
|
||||
|
||||
## Requirements to build native modules
|
||||
|
||||
We rely on Github Actions `windows-latest` plus a few extra utilities as per [the workflow](https://github.com/vector-im/element-desktop/blob/develop/.github/workflows/build_windows.yaml).
|
||||
|
||||
If you want to build native modules, make sure that the following tools are installed on your system.
|
||||
|
||||
- [Git for Windows](https://git-scm.com/download/win)
|
||||
- [Node 16](https://nodejs.org)
|
||||
- [Python 3](https://www.python.org/downloads/) (if you type 'python' into command prompt it will offer to install it from the windows store)
|
||||
- [Strawberry Perl](https://strawberryperl.com/)
|
||||
- [Rustup](https://rustup.rs/)
|
||||
- [NASM](https://www.nasm.us/)
|
||||
- [Build Tools for Visual Studio 2019](https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2019) with the following configuration:
|
||||
- On the Workloads tab:
|
||||
- Desktop & Mobile -> C++ build tools
|
||||
- On the Individual components tab:
|
||||
- MSVC VS 2019 C++ build tools
|
||||
- Windows 10 SDK (latest version available)
|
||||
- C++ CMake tools for Windows
|
||||
- [Node 14](https://nodejs.org)
|
||||
- [Python 3](https://www.python.org/downloads/)
|
||||
- [Strawberry Perl](https://strawberryperl.com/)
|
||||
- [Rust](https://rustup.rs/)
|
||||
- [Build Tools for Visual Studio 2019](https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2019) with the following configuration:
|
||||
- On the Workloads tab:
|
||||
- Desktop & Mobile -> C++ build tools
|
||||
- On the Individual components tab:
|
||||
- MSVC VS 2019 C++ build tools
|
||||
- Windows 10 SDK (latest version available)
|
||||
- C++ CMake tools for Windows
|
||||
|
||||
Once installed make sure all those utilities are accessible in your `PATH`.
|
||||
|
||||
If you want to be able to build x86 targets from an x64 host install the right toolchain:
|
||||
|
||||
```cmd
|
||||
rustup toolchain install stable-i686-pc-windows-msvc
|
||||
rustup target add i686-pc-windows-msvc
|
||||
```
|
||||
|
||||
In order to load all the C++ utilities installed by Visual Studio you can run the following in a terminal window.
|
||||
|
||||
```
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" amd64
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64
|
||||
```
|
||||
|
||||
You can replace `amd64` with `x86` depending on your CPU architecture.
|
||||
|
||||
@@ -1,14 +1,6 @@
|
||||
{
|
||||
"update_base_url": "https://packages.element.io/nightly/update/",
|
||||
"default_server_name": "matrix.org",
|
||||
"default_server_config": {
|
||||
"m.homeserver": {
|
||||
"base_url": "https://matrix-client.matrix.org"
|
||||
},
|
||||
"m.identity_server": {
|
||||
"base_url": "https://vector.im"
|
||||
}
|
||||
},
|
||||
"brand": "Element Nightly",
|
||||
"integrations_ui_url": "https://scalar.vector.im/",
|
||||
"integrations_rest_url": "https://scalar.vector.im/api",
|
||||
@@ -19,11 +11,20 @@
|
||||
"https://scalar-staging.vector.im/api",
|
||||
"https://scalar-staging.riot.im/scalar/api"
|
||||
],
|
||||
"hosting_signup_link": "https://element.io/matrix-services?utm_source=element-web&utm_medium=web",
|
||||
"bug_report_endpoint_url": "https://element.io/bugreports/submit",
|
||||
"uisi_autorageshake_app": "element-auto-uisi",
|
||||
"show_labs_settings": true,
|
||||
"room_directory": {
|
||||
"servers": ["matrix.org", "gitter.im", "libera.chat"]
|
||||
"showLabsSettings": true,
|
||||
"piwik": {
|
||||
"url": "https://piwik.riot.im/",
|
||||
"siteId": 1,
|
||||
"policyUrl": "https://element.io/cookie-policy"
|
||||
},
|
||||
"roomDirectory": {
|
||||
"servers": [
|
||||
"matrix.org",
|
||||
"gitter.im",
|
||||
"libera.chat"
|
||||
]
|
||||
},
|
||||
"enable_presence_by_hs_url": {
|
||||
"https://matrix.org": false,
|
||||
@@ -44,16 +45,10 @@
|
||||
"environment": "nightly"
|
||||
},
|
||||
"posthog": {
|
||||
"project_api_key": "phc_Jzsm6DTm6V2705zeU5dcNvQDlonOR68XvX2sh1sEOHO",
|
||||
"api_host": "https://posthog.element.io"
|
||||
"projectApiKey": "phc_Jzsm6DTm6V2705zeU5dcNvQDlonOR68XvX2sh1sEOHO",
|
||||
"apiHost": "https://posthog.hss.element.io"
|
||||
},
|
||||
"privacy_policy_url": "https://element.io/cookie-policy",
|
||||
"features": {
|
||||
"feature_spotlight": true,
|
||||
"feature_video_rooms": true
|
||||
},
|
||||
"element_call": {
|
||||
"url": "https://element-call-livekit.netlify.app"
|
||||
},
|
||||
"map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx"
|
||||
"feature_spaces_metaspaces": true
|
||||
}
|
||||
}
|
||||
|
||||
12
element.io/nightly/control.template
Normal file
12
element.io/nightly/control.template
Normal file
@@ -0,0 +1,12 @@
|
||||
Package: element-nightly
|
||||
License: Apache-2.0
|
||||
Vendor: support@element.io
|
||||
Architecture: amd64
|
||||
Maintainer: support@element.io
|
||||
Depends: libgtk-3-0, libnotify4, libnss3, libxss1, libxtst6, xdg-utils, libatspi2.0-0, libuuid1, libsecret-1-0, libsqlcipher0
|
||||
Recommends: libappindicator3-1
|
||||
Section: net
|
||||
Priority: extra
|
||||
Homepage: https://element.io/
|
||||
Description:
|
||||
riot.im A feature-rich client for Matrix.org (nightly unstable build).
|
||||
@@ -0,0 +1,9 @@
|
||||
Package: riot-nightly
|
||||
Version: 2020071502
|
||||
Depends: element-nightly
|
||||
Maintainer: packages@element.io
|
||||
Architecture: all
|
||||
Priority: optional
|
||||
Section: oldlibs
|
||||
Description: transitional package
|
||||
This is a transitional package. It can safely be removed.
|
||||
81
element.io/release/conf_distributions
Normal file
81
element.io/release/conf_distributions
Normal file
@@ -0,0 +1,81 @@
|
||||
Origin: riot.im
|
||||
Codename: default
|
||||
Architectures: amd64 i386 source
|
||||
Components: main
|
||||
SignWith: D7B0B66941D01538
|
||||
Tracking: minimal
|
||||
|
||||
Origin: riot.im
|
||||
Suite: oldoldstable
|
||||
Codename: jessie
|
||||
Architectures: amd64 i386 source
|
||||
Components: main
|
||||
SignWith: D7B0B66941D01538
|
||||
Tracking: minimal
|
||||
|
||||
Origin: riot.im
|
||||
Suite: oldstable
|
||||
Codename: stretch
|
||||
Architectures: amd64 i386 source
|
||||
Components: main
|
||||
SignWith: D7B0B66941D01538
|
||||
Tracking: minimal
|
||||
|
||||
Origin: riot.im
|
||||
Suite: stable
|
||||
Codename: buster
|
||||
Architectures: amd64 i386 source
|
||||
Components: main
|
||||
SignWith: D7B0B66941D01538
|
||||
Tracking: minimal
|
||||
|
||||
Origin: riot.im
|
||||
Suite: testing
|
||||
Codename: bullseye
|
||||
Architectures: amd64 i386 source
|
||||
Components: main
|
||||
SignWith: D7B0B66941D01538
|
||||
Tracking: minimal
|
||||
|
||||
Origin: riot.im
|
||||
Suite: unstable
|
||||
Codename: sid
|
||||
Architectures: amd64 i386 source
|
||||
Components: main
|
||||
SignWith: D7B0B66941D01538
|
||||
Tracking: minimal
|
||||
|
||||
Origin: riot.im
|
||||
Codename: xenial
|
||||
Architectures: amd64 i386 source
|
||||
Components: main
|
||||
SignWith: D7B0B66941D01538
|
||||
Tracking: minimal
|
||||
|
||||
Origin: riot.im
|
||||
Codename: bionic
|
||||
Architectures: amd64 i386 source
|
||||
Components: main
|
||||
SignWith: D7B0B66941D01538
|
||||
Tracking: minimal
|
||||
|
||||
Origin: riot.im
|
||||
Codename: cosmic
|
||||
Architectures: amd64 i386 source
|
||||
Components: main
|
||||
SignWith: D7B0B66941D01538
|
||||
Tracking: minimal
|
||||
|
||||
Origin: riot.im
|
||||
Codename: disco
|
||||
Architectures: amd64 i386 source
|
||||
Components: main
|
||||
SignWith: D7B0B66941D01538
|
||||
Tracking: minimal
|
||||
|
||||
Origin: riot.im
|
||||
Codename: eoan
|
||||
Architectures: amd64 i386 source
|
||||
Components: main
|
||||
SignWith: D7B0B66941D01538
|
||||
Tracking: minimal
|
||||
@@ -1,14 +1,6 @@
|
||||
{
|
||||
"update_base_url": "https://packages.element.io/desktop/update/",
|
||||
"default_server_name": "matrix.org",
|
||||
"default_server_config": {
|
||||
"m.homeserver": {
|
||||
"base_url": "https://matrix-client.matrix.org"
|
||||
},
|
||||
"m.identity_server": {
|
||||
"base_url": "https://vector.im"
|
||||
}
|
||||
},
|
||||
"brand": "Element",
|
||||
"integrations_ui_url": "https://scalar.vector.im/",
|
||||
"integrations_rest_url": "https://scalar.vector.im/api",
|
||||
@@ -19,12 +11,21 @@
|
||||
"https://scalar-staging.vector.im/api",
|
||||
"https://scalar-staging.riot.im/scalar/api"
|
||||
],
|
||||
"hosting_signup_link": "https://element.io/matrix-services?utm_source=element-web&utm_medium=web",
|
||||
"bug_report_endpoint_url": "https://element.io/bugreports/submit",
|
||||
"uisi_autorageshake_app": "element-auto-uisi",
|
||||
"room_directory": {
|
||||
"servers": ["matrix.org", "gitter.im", "libera.chat"]
|
||||
"roomDirectory": {
|
||||
"servers": [
|
||||
"matrix.org",
|
||||
"gitter.im",
|
||||
"libera.chat"
|
||||
]
|
||||
},
|
||||
"showLabsSettings": false,
|
||||
"piwik": {
|
||||
"url": "https://piwik.riot.im/",
|
||||
"siteId": 1,
|
||||
"policyUrl": "https://element.io/cookie-policy"
|
||||
},
|
||||
"show_labs_settings": false,
|
||||
"enable_presence_by_hs_url": {
|
||||
"https://matrix.org": false,
|
||||
"https://matrix-client.matrix.org": false
|
||||
@@ -38,11 +39,5 @@
|
||||
"url": "https://element.io/cookie-policy",
|
||||
"text": "Cookie Policy"
|
||||
}
|
||||
],
|
||||
"posthog": {
|
||||
"project_api_key": "phc_Jzsm6DTm6V2705zeU5dcNvQDlonOR68XvX2sh1sEOHO",
|
||||
"api_host": "https://posthog.element.io"
|
||||
},
|
||||
"privacy_policy_url": "https://element.io/cookie-policy",
|
||||
"map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx"
|
||||
]
|
||||
}
|
||||
|
||||
14
element.io/release/control.template
Normal file
14
element.io/release/control.template
Normal file
@@ -0,0 +1,14 @@
|
||||
Package: element-desktop
|
||||
License: Apache-2.0
|
||||
Vendor: support@element.io
|
||||
Architecture: amd64
|
||||
Maintainer: support@element.io
|
||||
Depends: libgtk-3-0, libnotify4, libnss3, libxss1, libxtst6, xdg-utils, libatspi2.0-0, libuuid1, libsecret-1-0, libsqlcipher0
|
||||
Recommends: libappindicator3-1
|
||||
Replaces: riot-desktop (<< 1.7.0), riot-web (<< 1.7.0)
|
||||
Breaks: riot-desktop (<< 1.7.0), riot-web (<< 1.7.0)
|
||||
Section: net
|
||||
Priority: extra
|
||||
Homepage: https://element.io/
|
||||
Description:
|
||||
A feature-rich client for Matrix.org
|
||||
9
element.io/release/riot-desktop_1.7.0_all/DEBIAN/control
Normal file
9
element.io/release/riot-desktop_1.7.0_all/DEBIAN/control
Normal file
@@ -0,0 +1,9 @@
|
||||
Package: riot-desktop
|
||||
Version: 1.7.0
|
||||
Depends: element-desktop
|
||||
Maintainer: packages@element.io
|
||||
Architecture: all
|
||||
Priority: optional
|
||||
Section: oldlibs
|
||||
Description: transitional package
|
||||
This is a transitional package. It can safely be removed.
|
||||
@@ -14,27 +14,28 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import path from "path";
|
||||
import childProcess from "child_process";
|
||||
const path = require('path');
|
||||
const childProcess = require('child_process');
|
||||
|
||||
import HakEnv from "../../scripts/hak/hakEnv";
|
||||
import { DependencyInfo } from "../../scripts/hak/dep";
|
||||
module.exports = async function(hakEnv, moduleInfo) {
|
||||
await buildKeytar(hakEnv, moduleInfo);
|
||||
};
|
||||
|
||||
export default async function buildKeytar(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
|
||||
async function buildKeytar(hakEnv, moduleInfo) {
|
||||
const env = hakEnv.makeGypEnv();
|
||||
|
||||
console.log("Running yarn with env", env);
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
await new Promise((resolve, reject) => {
|
||||
const proc = childProcess.spawn(
|
||||
path.join(moduleInfo.nodeModuleBinDir, "node-gyp" + (hakEnv.isWin() ? ".cmd" : "")),
|
||||
["rebuild", "--arch", hakEnv.getTargetArch()],
|
||||
path.join(moduleInfo.nodeModuleBinDir, 'node-gyp' + (hakEnv.isWin() ? '.cmd' : '')),
|
||||
['rebuild'],
|
||||
{
|
||||
cwd: moduleInfo.moduleBuildDir,
|
||||
env,
|
||||
stdio: "inherit",
|
||||
stdio: 'inherit',
|
||||
},
|
||||
);
|
||||
proc.on("exit", (code) => {
|
||||
proc.on('exit', (code) => {
|
||||
code ? reject(code) : resolve();
|
||||
});
|
||||
});
|
||||
@@ -14,20 +14,17 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import childProcess from "child_process";
|
||||
const childProcess = require('child_process');
|
||||
|
||||
import HakEnv from "../../scripts/hak/hakEnv";
|
||||
import { DependencyInfo } from "../../scripts/hak/dep";
|
||||
|
||||
export default async function (hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
|
||||
const tools = [["python", "--version"]]; // node-gyp uses python for reasons beyond comprehension
|
||||
module.exports = async function(hakEnv, moduleInfo) {
|
||||
const tools = [['python', '--version']]; // node-gyp uses python for reasons beyond comprehension
|
||||
|
||||
for (const tool of tools) {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
await new Promise((resolve, reject) => {
|
||||
const proc = childProcess.spawn(tool[0], tool.slice(1), {
|
||||
stdio: ["ignore"],
|
||||
stdio: ['ignore'],
|
||||
});
|
||||
proc.on("exit", (code) => {
|
||||
proc.on('exit', (code) => {
|
||||
if (code !== 0) {
|
||||
reject("Can't find " + tool);
|
||||
} else {
|
||||
@@ -36,4 +33,4 @@ export default async function (hakEnv: HakEnv, moduleInfo: DependencyInfo): Prom
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"scripts": {
|
||||
"check": "check.ts",
|
||||
"build": "build.ts"
|
||||
"check": "check.js",
|
||||
"build": "build.js"
|
||||
},
|
||||
"copy": "build/Release/keytar.node",
|
||||
"dependencies": {
|
||||
|
||||
303
hak/matrix-seshat/build.js
Normal file
303
hak/matrix-seshat/build.js
Normal file
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
Copyright 2020-2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
const path = require('path');
|
||||
const childProcess = require('child_process');
|
||||
|
||||
const mkdirp = require('mkdirp');
|
||||
const fsExtra = require('fs-extra');
|
||||
|
||||
module.exports = async function(hakEnv, moduleInfo) {
|
||||
if (hakEnv.isWin()) {
|
||||
await buildOpenSslWin(hakEnv, moduleInfo);
|
||||
await buildSqlCipherWin(hakEnv, moduleInfo);
|
||||
} else if (hakEnv.isMac()) {
|
||||
await buildSqlCipherUnix(hakEnv, moduleInfo);
|
||||
}
|
||||
await buildMatrixSeshat(hakEnv, moduleInfo);
|
||||
};
|
||||
|
||||
async function buildOpenSslWin(hakEnv, moduleInfo) {
|
||||
const version = moduleInfo.cfg.dependencies.openssl;
|
||||
const openSslDir = path.join(moduleInfo.moduleTargetDotHakDir, `openssl-${version}`);
|
||||
|
||||
const openSslArch = hakEnv.getTargetArch() === 'x64' ? 'VC-WIN64A' : 'VC-WIN32';
|
||||
|
||||
console.log("Building openssl in " + openSslDir);
|
||||
await new Promise((resolve, reject) => {
|
||||
const proc = childProcess.spawn(
|
||||
'perl',
|
||||
[
|
||||
'Configure',
|
||||
'--prefix=' + moduleInfo.depPrefix,
|
||||
// sqlcipher only uses about a tiny part of openssl. We link statically
|
||||
// so will only pull in the symbols we use, but we may as well turn off
|
||||
// as much as possible to save on build time.
|
||||
'no-afalgeng',
|
||||
'no-capieng',
|
||||
'no-cms',
|
||||
'no-ct',
|
||||
'no-deprecated',
|
||||
'no-dgram',
|
||||
'no-dso',
|
||||
'no-ec',
|
||||
'no-ec2m',
|
||||
'no-gost',
|
||||
'no-nextprotoneg',
|
||||
'no-ocsp',
|
||||
'no-sock',
|
||||
'no-srp',
|
||||
'no-srtp',
|
||||
'no-tests',
|
||||
'no-ssl',
|
||||
'no-tls',
|
||||
'no-dtls',
|
||||
'no-shared',
|
||||
'no-aria',
|
||||
'no-camellia',
|
||||
'no-cast',
|
||||
'no-chacha',
|
||||
'no-cmac',
|
||||
'no-des',
|
||||
'no-dh',
|
||||
'no-dsa',
|
||||
'no-ecdh',
|
||||
'no-ecdsa',
|
||||
'no-idea',
|
||||
'no-md4',
|
||||
'no-mdc2',
|
||||
'no-ocb',
|
||||
'no-poly1305',
|
||||
'no-rc2',
|
||||
'no-rc4',
|
||||
'no-rmd160',
|
||||
'no-scrypt',
|
||||
'no-seed',
|
||||
'no-siphash',
|
||||
'no-sm2',
|
||||
'no-sm3',
|
||||
'no-sm4',
|
||||
'no-whirlpool',
|
||||
openSslArch,
|
||||
],
|
||||
{
|
||||
cwd: openSslDir,
|
||||
stdio: 'inherit',
|
||||
},
|
||||
);
|
||||
proc.on('exit', (code) => {
|
||||
code ? reject(code) : resolve();
|
||||
});
|
||||
});
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
const proc = childProcess.spawn(
|
||||
'nmake',
|
||||
['build_libs'],
|
||||
{
|
||||
cwd: openSslDir,
|
||||
stdio: 'inherit',
|
||||
},
|
||||
);
|
||||
proc.on('exit', (code) => {
|
||||
code ? reject(code) : resolve();
|
||||
});
|
||||
});
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
const proc = childProcess.spawn(
|
||||
'nmake',
|
||||
['install_dev'],
|
||||
{
|
||||
cwd: openSslDir,
|
||||
stdio: 'inherit',
|
||||
},
|
||||
);
|
||||
proc.on('exit', (code) => {
|
||||
code ? reject(code) : resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function buildSqlCipherWin(hakEnv, moduleInfo) {
|
||||
const version = moduleInfo.cfg.dependencies.sqlcipher;
|
||||
const sqlCipherDir = path.join(moduleInfo.moduleTargetDotHakDir, `sqlcipher-${version}`);
|
||||
const buildDir = path.join(sqlCipherDir, 'bld');
|
||||
|
||||
await mkdirp(buildDir);
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
const proc = childProcess.spawn(
|
||||
'nmake',
|
||||
['/f', path.join('..', 'Makefile.msc'), 'libsqlite3.lib', 'TOP=..'],
|
||||
{
|
||||
cwd: buildDir,
|
||||
stdio: 'inherit',
|
||||
env: Object.assign({}, process.env, {
|
||||
CCOPTS: "-DSQLITE_HAS_CODEC -I" + path.join(moduleInfo.depPrefix, 'include'),
|
||||
LTLIBPATHS: "/LIBPATH:" + path.join(moduleInfo.depPrefix, 'lib'),
|
||||
LTLIBS: "libcrypto.lib",
|
||||
}),
|
||||
},
|
||||
);
|
||||
proc.on('exit', (code) => {
|
||||
code ? reject(code) : resolve();
|
||||
});
|
||||
});
|
||||
|
||||
await fsExtra.copy(
|
||||
path.join(buildDir, 'libsqlite3.lib'),
|
||||
path.join(moduleInfo.depPrefix, 'lib', 'sqlcipher.lib'),
|
||||
);
|
||||
|
||||
await fsExtra.copy(
|
||||
path.join(buildDir, 'sqlite3.h'),
|
||||
path.join(moduleInfo.depPrefix, 'include', 'sqlcipher.h'),
|
||||
);
|
||||
}
|
||||
|
||||
async function buildSqlCipherUnix(hakEnv, moduleInfo) {
|
||||
const version = moduleInfo.cfg.dependencies.sqlcipher;
|
||||
const sqlCipherDir = path.join(moduleInfo.moduleTargetDotHakDir, `sqlcipher-${version}`);
|
||||
|
||||
const args = [
|
||||
'--prefix=' + moduleInfo.depPrefix + '',
|
||||
'--enable-tempstore=yes',
|
||||
'--enable-shared=no',
|
||||
];
|
||||
|
||||
if (hakEnv.isMac()) {
|
||||
args.push('--with-crypto-lib=commoncrypto');
|
||||
}
|
||||
|
||||
if (!hakEnv.isHost()) {
|
||||
// In the nonsense world of `configure`, it is assumed you are building
|
||||
// a compiler like `gcc`, so the `host` option actually means the target
|
||||
// the build output runs on.
|
||||
args.push(`--host=${hakEnv.getTargetId()}`);
|
||||
}
|
||||
|
||||
const cflags = [
|
||||
'-DSQLITE_HAS_CODEC',
|
||||
];
|
||||
|
||||
if (!hakEnv.isHost()) {
|
||||
// `clang` uses more logical option naming.
|
||||
cflags.push(`--target=${hakEnv.getTargetId()}`);
|
||||
}
|
||||
|
||||
if (cflags.length) {
|
||||
args.push(`CFLAGS=${cflags.join(' ')}`);
|
||||
}
|
||||
|
||||
const ldflags = [];
|
||||
|
||||
if (hakEnv.isMac()) {
|
||||
ldflags.push('-framework Security');
|
||||
ldflags.push('-framework Foundation');
|
||||
}
|
||||
|
||||
if (ldflags.length) {
|
||||
args.push(`LDFLAGS=${ldflags.join(' ')}`);
|
||||
}
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
const proc = childProcess.spawn(
|
||||
path.join(sqlCipherDir, 'configure'),
|
||||
args,
|
||||
{
|
||||
cwd: sqlCipherDir,
|
||||
stdio: 'inherit',
|
||||
},
|
||||
);
|
||||
proc.on('exit', (code) => {
|
||||
code ? reject(code) : resolve();
|
||||
});
|
||||
});
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
const proc = childProcess.spawn(
|
||||
'make',
|
||||
[],
|
||||
{
|
||||
cwd: sqlCipherDir,
|
||||
stdio: 'inherit',
|
||||
},
|
||||
);
|
||||
proc.on('exit', (code) => {
|
||||
code ? reject(code) : resolve();
|
||||
});
|
||||
});
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
const proc = childProcess.spawn(
|
||||
'make',
|
||||
['install'],
|
||||
{
|
||||
cwd: sqlCipherDir,
|
||||
stdio: 'inherit',
|
||||
},
|
||||
);
|
||||
proc.on('exit', (code) => {
|
||||
code ? reject(code) : resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function buildMatrixSeshat(hakEnv, moduleInfo) {
|
||||
// seshat now uses n-api so we shouldn't need to specify a node version to
|
||||
// build against, but it does seems to still need something in here, so leaving
|
||||
// it for now: we should confirm how much of this it still actually needs.
|
||||
const env = hakEnv.makeGypEnv();
|
||||
|
||||
if (!hakEnv.isLinux()) {
|
||||
Object.assign(env, {
|
||||
SQLCIPHER_STATIC: 1,
|
||||
SQLCIPHER_LIB_DIR: path.join(moduleInfo.depPrefix, 'lib'),
|
||||
SQLCIPHER_INCLUDE_DIR: path.join(moduleInfo.depPrefix, 'include'),
|
||||
});
|
||||
}
|
||||
|
||||
if (hakEnv.isWin()) {
|
||||
env.RUSTFLAGS = '-Ctarget-feature=+crt-static -Clink-args=libcrypto.lib';
|
||||
// Note that in general, you can specify targets in Rust without having to have
|
||||
// the matching toolchain, however for this, cargo gets confused when building
|
||||
// the build scripts since they run on the host, but vcvarsall.bat sets the c
|
||||
// compiler in the path to be the one for the target, so we just use the matching
|
||||
// toolchain for the target architecture which makes everything happy.
|
||||
env.RUSTUP_TOOLCHAIN = `stable-${hakEnv.getTargetId()}`;
|
||||
}
|
||||
|
||||
if (!hakEnv.isHost()) {
|
||||
env.CARGO_BUILD_TARGET = hakEnv.getTargetId();
|
||||
}
|
||||
|
||||
console.log("Running neon with env", env);
|
||||
await new Promise((resolve, reject) => {
|
||||
const proc = childProcess.spawn(
|
||||
path.join(moduleInfo.nodeModuleBinDir, 'neon' + (hakEnv.isWin() ? '.cmd' : '')),
|
||||
['build', '--release'],
|
||||
{
|
||||
cwd: moduleInfo.moduleBuildDir,
|
||||
env,
|
||||
stdio: 'inherit',
|
||||
},
|
||||
);
|
||||
proc.on('exit', (code) => {
|
||||
code ? reject(code) : resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
Copyright 2020-2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
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 childProcess from "child_process";
|
||||
|
||||
import HakEnv from "../../scripts/hak/hakEnv";
|
||||
import { DependencyInfo } from "../../scripts/hak/dep";
|
||||
|
||||
export default async function (hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
|
||||
const env = hakEnv.makeGypEnv();
|
||||
|
||||
if (!hakEnv.isHost()) {
|
||||
env.CARGO_BUILD_TARGET = hakEnv.getTargetId();
|
||||
}
|
||||
|
||||
console.log("Running yarn install");
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const proc = childProcess.spawn(
|
||||
"yarn" + (hakEnv.isWin() ? ".cmd" : ""),
|
||||
["install"],
|
||||
{
|
||||
cwd: moduleInfo.moduleBuildDir,
|
||||
env,
|
||||
shell: true,
|
||||
stdio: "inherit",
|
||||
},
|
||||
);
|
||||
proc.on("exit", (code) => {
|
||||
code ? reject(code) : resolve();
|
||||
});
|
||||
});
|
||||
|
||||
const buildTarget = hakEnv.wantsStaticSqlCipher() ? "build-bundled" : "build";
|
||||
|
||||
console.log("Running yarn build");
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const proc = childProcess.spawn(
|
||||
"yarn" + (hakEnv.isWin() ? ".cmd" : ""),
|
||||
["run", buildTarget],
|
||||
{
|
||||
cwd: moduleInfo.moduleBuildDir,
|
||||
env,
|
||||
shell: true,
|
||||
stdio: "inherit",
|
||||
},
|
||||
);
|
||||
proc.on("exit", (code) => {
|
||||
code ? reject(code) : resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
82
hak/matrix-seshat/check.js
Normal file
82
hak/matrix-seshat/check.js
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
Copyright 2020-2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
const childProcess = require('child_process');
|
||||
const fsProm = require('fs').promises;
|
||||
|
||||
module.exports = async function(hakEnv, moduleInfo) {
|
||||
// of course tcl doesn't have a --version
|
||||
if (!hakEnv.isLinux()) {
|
||||
await new Promise((resolve, reject) => {
|
||||
const proc = childProcess.spawn('tclsh', [], {
|
||||
stdio: ['pipe', 'ignore', 'ignore'],
|
||||
});
|
||||
proc.on('exit', (code) => {
|
||||
if (code !== 0) {
|
||||
reject("Can't find tclsh - have you installed TCL?");
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
proc.stdin.end();
|
||||
});
|
||||
}
|
||||
|
||||
const tools = [
|
||||
['rustc', '--version'],
|
||||
['python', '--version'], // node-gyp uses python for reasons beyond comprehension
|
||||
];
|
||||
if (hakEnv.isWin()) {
|
||||
tools.push(['perl', '--version']); // for openssl configure
|
||||
tools.push(['patch', '--version']); // to patch sqlcipher Makefile.msc
|
||||
tools.push(['nmake', '/?']);
|
||||
} else {
|
||||
tools.push(['make', '--version']);
|
||||
}
|
||||
|
||||
for (const tool of tools) {
|
||||
await new Promise((resolve, reject) => {
|
||||
const proc = childProcess.spawn(tool[0], tool.slice(1), {
|
||||
stdio: ['ignore'],
|
||||
});
|
||||
proc.on('exit', (code) => {
|
||||
if (code !== 0) {
|
||||
reject("Can't find " + tool);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Ensure Rust target exists (nb. we avoid depending on rustup)
|
||||
await new Promise((resolve, reject) => {
|
||||
const rustc = childProcess.execFile('rustc', [
|
||||
'--target', hakEnv.getTargetId(), '-o', 'tmp', '-',
|
||||
], (err, out) => {
|
||||
if (err) {
|
||||
reject(
|
||||
"rustc can't build for target " + hakEnv.getTargetId() +
|
||||
": ensure target is installed via `rustup target add " + hakEnv.getTargetId() + "` " +
|
||||
"or your package manager if not using `rustup`",
|
||||
);
|
||||
}
|
||||
fsProm.unlink('tmp').then(resolve);
|
||||
});
|
||||
rustc.stdin.write('fn main() {}');
|
||||
rustc.stdin.end();
|
||||
});
|
||||
};
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
Copyright 2020-2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
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 childProcess from "child_process";
|
||||
import fsProm from "fs/promises";
|
||||
|
||||
import HakEnv from "../../scripts/hak/hakEnv";
|
||||
import { DependencyInfo } from "../../scripts/hak/dep";
|
||||
|
||||
export default async function (hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
|
||||
const tools = [
|
||||
["rustc", "--version"],
|
||||
["python", "--version"], // node-gyp uses python for reasons beyond comprehension
|
||||
];
|
||||
if (hakEnv.isWin()) {
|
||||
tools.push(["perl", "--version"]); // for openssl configure
|
||||
tools.push(["nasm", "-v"]); // for openssl building
|
||||
tools.push(["patch", "--version"]); // to patch sqlcipher Makefile.msc
|
||||
tools.push(["nmake", "/?"]);
|
||||
} else {
|
||||
tools.push(["make", "--version"]);
|
||||
}
|
||||
|
||||
for (const tool of tools) {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const proc = childProcess.spawn(tool[0], tool.slice(1), {
|
||||
stdio: ["ignore"],
|
||||
});
|
||||
proc.on("exit", (code) => {
|
||||
if (code !== 0) {
|
||||
reject("Can't find " + tool);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Ensure Rust target exists (nb. we avoid depending on rustup)
|
||||
await new Promise((resolve, reject) => {
|
||||
const rustc = childProcess.execFile(
|
||||
"rustc",
|
||||
["--target", hakEnv.getTargetId(), "--emit=obj", "-o", "tmp", "-"],
|
||||
(err, out) => {
|
||||
if (err) {
|
||||
reject(
|
||||
"rustc can't build for target " +
|
||||
hakEnv.getTargetId() +
|
||||
": ensure target is installed via `rustup target add " +
|
||||
hakEnv.getTargetId() +
|
||||
"` " +
|
||||
"or your package manager if not using `rustup`",
|
||||
);
|
||||
}
|
||||
fsProm.unlink("tmp").then(resolve);
|
||||
},
|
||||
);
|
||||
rustc.stdin!.write("fn main() {}");
|
||||
rustc.stdout!.pipe(process.stdout);
|
||||
rustc.stderr!.pipe(process.stderr);
|
||||
rustc.stdin!.end();
|
||||
});
|
||||
}
|
||||
130
hak/matrix-seshat/fetchDeps.js
Normal file
130
hak/matrix-seshat/fetchDeps.js
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
const path = require('path');
|
||||
const childProcess = require('child_process');
|
||||
|
||||
const fs = require('fs');
|
||||
const fsProm = require('fs').promises;
|
||||
const needle = require('needle');
|
||||
const tar = require('tar');
|
||||
|
||||
module.exports = async function(hakEnv, moduleInfo) {
|
||||
if (!hakEnv.isLinux()) {
|
||||
await getSqlCipher(hakEnv, moduleInfo);
|
||||
}
|
||||
|
||||
if (hakEnv.isWin()) {
|
||||
await getOpenSsl(hakEnv, moduleInfo);
|
||||
}
|
||||
};
|
||||
|
||||
async function getSqlCipher(hakEnv, moduleInfo) {
|
||||
const version = moduleInfo.cfg.dependencies.sqlcipher;
|
||||
const sqlCipherDir = path.join(moduleInfo.moduleTargetDotHakDir, `sqlcipher-${version}`);
|
||||
|
||||
let haveSqlcipher;
|
||||
try {
|
||||
await fsProm.stat(sqlCipherDir);
|
||||
haveSqlcipher = true;
|
||||
} catch (e) {
|
||||
haveSqlcipher = false;
|
||||
}
|
||||
|
||||
if (haveSqlcipher) return;
|
||||
|
||||
const sqlCipherTarball = path.join(moduleInfo.moduleDotHakDir, `sqlcipher-${version}.tar.gz`);
|
||||
let haveSqlcipherTar;
|
||||
try {
|
||||
await fsProm.stat(sqlCipherTarball);
|
||||
haveSqlcipherTar = true;
|
||||
} catch (e) {
|
||||
haveSqlcipherTar = false;
|
||||
}
|
||||
if (!haveSqlcipherTar) {
|
||||
const bob = needle('get', `https://github.com/sqlcipher/sqlcipher/archive/v${version}.tar.gz`, {
|
||||
follow: 10,
|
||||
output: sqlCipherTarball,
|
||||
});
|
||||
await bob;
|
||||
}
|
||||
|
||||
// Extract the tarball to per-target directories, then we avoid cross-contaiminating archs
|
||||
await tar.x({
|
||||
file: sqlCipherTarball,
|
||||
cwd: moduleInfo.moduleTargetDotHakDir,
|
||||
});
|
||||
|
||||
if (hakEnv.isWin()) {
|
||||
// On Windows, we need to patch the makefile because it forces TEMP_STORE to
|
||||
// default to files (1) but the README specifically says you '*must*' set it
|
||||
// set it to 2 (default to memory).
|
||||
const patchFile = path.join(moduleInfo.moduleHakDir, `sqlcipher-${version}-win.patch`);
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
const readStream = fs.createReadStream(patchFile);
|
||||
|
||||
const proc = childProcess.spawn(
|
||||
'patch',
|
||||
['-p1'],
|
||||
{
|
||||
cwd: sqlCipherDir,
|
||||
stdio: ['pipe', 'inherit', 'inherit'],
|
||||
},
|
||||
);
|
||||
proc.on('exit', (code) => {
|
||||
code ? reject(code) : resolve();
|
||||
});
|
||||
readStream.pipe(proc.stdin);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function getOpenSsl(hakEnv, moduleInfo) {
|
||||
const version = moduleInfo.cfg.dependencies.openssl;
|
||||
const openSslDir = path.join(moduleInfo.moduleTargetDotHakDir, `openssl-${version}`);
|
||||
|
||||
let haveOpenSsl;
|
||||
try {
|
||||
await fsProm.stat(openSslDir);
|
||||
haveOpenSsl = true;
|
||||
} catch (e) {
|
||||
haveOpenSsl = false;
|
||||
}
|
||||
|
||||
if (haveOpenSsl) return;
|
||||
|
||||
const openSslTarball = path.join(moduleInfo.moduleDotHakDir, `openssl-${version}.tar.gz`);
|
||||
let haveOpenSslTar;
|
||||
try {
|
||||
await fsProm.stat(openSslTarball);
|
||||
haveOpenSslTar = true;
|
||||
} catch (e) {
|
||||
haveOpenSslTar = false;
|
||||
}
|
||||
if (!haveOpenSslTar) {
|
||||
await needle('get', `https://www.openssl.org/source/openssl-${version}.tar.gz`, {
|
||||
follow: 10,
|
||||
output: openSslTarball,
|
||||
});
|
||||
}
|
||||
|
||||
console.log("extracting " + openSslTarball + " in " + moduleInfo.moduleTargetDotHakDir);
|
||||
await tar.x({
|
||||
file: openSslTarball,
|
||||
cwd: moduleInfo.moduleTargetDotHakDir,
|
||||
});
|
||||
}
|
||||
@@ -1,7 +1,13 @@
|
||||
{
|
||||
"scripts": {
|
||||
"check": "check.ts",
|
||||
"build": "build.ts"
|
||||
"check": "check.js",
|
||||
"fetchDeps": "fetchDeps.js",
|
||||
"build": "build.js"
|
||||
},
|
||||
"copy": "index.node"
|
||||
"prune": "native",
|
||||
"copy": "native/index.node",
|
||||
"dependencies": {
|
||||
"openssl": "1.1.1f",
|
||||
"sqlcipher": "4.3.0"
|
||||
}
|
||||
}
|
||||
|
||||
14
hak/matrix-seshat/sqlcipher-4.3.0-win.patch
Normal file
14
hak/matrix-seshat/sqlcipher-4.3.0-win.patch
Normal file
@@ -0,0 +1,14 @@
|
||||
diff -Nur sqlcipher-4.3.0-orig/Makefile.msc sqlcipher-4.3.0-mod/Makefile.msc
|
||||
--- sqlcipher-4.3.0-orig/Makefile.msc 2019-12-20 16:40:26.000000000 +0000
|
||||
+++ sqlcipher-4.3.0-mod/Makefile.msc 2020-02-14 11:31:39.000000000 +0000
|
||||
@@ -985,8 +985,8 @@
|
||||
# default to file, 2 to default to memory, and 3 to force temporary
|
||||
# tables to always be in memory.
|
||||
#
|
||||
-TCC = $(TCC) -DSQLITE_TEMP_STORE=1
|
||||
-RCC = $(RCC) -DSQLITE_TEMP_STORE=1
|
||||
+TCC = $(TCC) -DSQLITE_TEMP_STORE=2
|
||||
+RCC = $(RCC) -DSQLITE_TEMP_STORE=2
|
||||
|
||||
# Enable/disable loadable extensions, and other optional features
|
||||
# based on configuration. (-DSQLITE_OMIT*, -DSQLITE_ENABLE*).
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
"target": "es2016",
|
||||
"sourceMap": false,
|
||||
"strict": true,
|
||||
"lib": ["es2020"]
|
||||
},
|
||||
"include": ["../scripts/@types/*.d.ts", "./**/*.ts"],
|
||||
"ts-node": {
|
||||
"transpileOnly": true
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
{
|
||||
"readKey": "a7688614897667993891-866e2615b0a22e6ccef56aea9b10e815efa3e1296752a7a30bd9925f1a8f33e7",
|
||||
|
||||
"upload": {
|
||||
"type": "json",
|
||||
"keySeparator": "|",
|
||||
"deprecate": "file",
|
||||
"features": ["plural_object", "filter_untranslated"],
|
||||
"files": [
|
||||
{
|
||||
"pattern": "src/i18n/strings/en_EN.json",
|
||||
"file": "element-desktop.json",
|
||||
"lang": "inherited"
|
||||
},
|
||||
{
|
||||
"group": "existing",
|
||||
"pattern": "src/i18n/strings/*.json",
|
||||
"file": "element-desktop.json",
|
||||
"excludes": ["src/i18n/strings/en_EN.json"],
|
||||
"lang": "${autodetectLang}"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"download": {
|
||||
"files": [
|
||||
{
|
||||
"conditions": "equals: ${file}, element-desktop.json",
|
||||
"output": "src/i18n/strings/${langLsrUnderscore}.json"
|
||||
}
|
||||
],
|
||||
"includeSourceLang": "${includeSourceLang|false}",
|
||||
"langAliases": {
|
||||
"en": "en-EN"
|
||||
}
|
||||
}
|
||||
}
|
||||
333
package.json
333
package.json
@@ -1,213 +1,134 @@
|
||||
{
|
||||
"name": "element-desktop",
|
||||
"productName": "Element",
|
||||
"main": "lib/electron-main.js",
|
||||
"version": "1.11.46",
|
||||
"description": "A feature-rich client for Matrix.org",
|
||||
"author": "Element",
|
||||
"homepage": "https://element.io",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vector-im/element-desktop"
|
||||
"name": "element-desktop",
|
||||
"productName": "Element",
|
||||
"main": "lib/electron-main.js",
|
||||
"version": "1.9.7",
|
||||
"description": "A feature-rich client for Matrix.org",
|
||||
"author": "Element",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vector-im/element-desktop"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"files": [],
|
||||
"scripts": {
|
||||
"i18n": "matrix-gen-i18n",
|
||||
"prunei18n": "matrix-prune-i18n",
|
||||
"diff-i18n": "cp src/i18n/strings/en_EN.json src/i18n/strings/en_EN_orig.json && matrix-gen-i18n && matrix-compare-i18n-files src/i18n/strings/en_EN_orig.json src/i18n/strings/en_EN.json",
|
||||
"mkdirs": "mkdirp packages deploys",
|
||||
"fetch": "yarn run mkdirs && node scripts/fetch-package.js",
|
||||
"asar-webapp": "asar p webapp webapp.asar",
|
||||
"start": "yarn run build:ts && yarn run build:res && electron .",
|
||||
"lint": "yarn lint:types && yarn lint:js",
|
||||
"lint:js": "eslint --max-warnings 0 src scripts hak",
|
||||
"lint:js-fix": "eslint --fix src scripts hak",
|
||||
"lint:types": "tsc --noEmit",
|
||||
"build:native": "yarn run hak",
|
||||
"build:native:universal": "yarn run hak --target x86_64-apple-darwin fetchandbuild && yarn run hak --target aarch64-apple-darwin fetchandbuild && yarn run hak --target x86_64-apple-darwin --target aarch64-apple-darwin copyandlink",
|
||||
"build:32": "yarn run build:ts && yarn run build:res && electron-builder --ia32",
|
||||
"build:64": "yarn run build:ts && yarn run build:res && electron-builder --x64",
|
||||
"build:universal": "yarn run build:ts && yarn run build:res && electron-builder --universal",
|
||||
"build": "yarn run build:ts && yarn run build:res && electron-builder",
|
||||
"build:ts": "tsc",
|
||||
"build:res": "node scripts/copy-res.js",
|
||||
"docker:setup": "docker build -t element-desktop-dockerbuild dockerbuild",
|
||||
"docker:build:native": "scripts/in-docker.sh yarn run hak",
|
||||
"docker:build": "scripts/in-docker.sh yarn run build",
|
||||
"docker:install": "scripts/in-docker.sh yarn install",
|
||||
"debrepo": "scripts/mkrepo.sh",
|
||||
"clean": "rimraf webapp.asar dist packages deploys lib",
|
||||
"hak": "node scripts/hak/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"auto-launch": "^5.0.5",
|
||||
"counterpart": "^0.18.6",
|
||||
"electron-store": "^6.0.1",
|
||||
"electron-window-state": "^5.0.3",
|
||||
"minimist": "^1.2.3",
|
||||
"png-to-ico": "^2.1.1",
|
||||
"request": "^2.88.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/auto-launch": "^5.0.1",
|
||||
"@types/counterpart": "^0.18.1",
|
||||
"@types/minimist": "^1.2.1",
|
||||
"@typescript-eslint/eslint-plugin": "^4.17.0",
|
||||
"@typescript-eslint/parser": "^4.17.0",
|
||||
"allchange": "^1.0.6",
|
||||
"asar": "^2.0.1",
|
||||
"chokidar": "^3.5.2",
|
||||
"electron": "13.5",
|
||||
"electron-builder": "22.11.4",
|
||||
"electron-builder-squirrel-windows": "22.11.4",
|
||||
"electron-devtools-installer": "^3.1.1",
|
||||
"electron-notarize": "^1.0.0",
|
||||
"eslint": "7.18.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-plugin-matrix-org": "github:matrix-org/eslint-plugin-matrix-org#2306b3d4da4eba908b256014b979f1d3d43d2945",
|
||||
"find-npm-prefix": "^1.0.2",
|
||||
"fs-extra": "^8.1.0",
|
||||
"glob": "^7.1.6",
|
||||
"matrix-web-i18n": "github:matrix-org/matrix-web-i18n",
|
||||
"mkdirp": "^1.0.3",
|
||||
"needle": "^2.5.0",
|
||||
"node-pre-gyp": "^0.15.0",
|
||||
"pacote": "^11.3.5",
|
||||
"rimraf": "^3.0.2",
|
||||
"tar": "^6.1.2",
|
||||
"typescript": "^4.1.3"
|
||||
},
|
||||
"hakDependencies": {
|
||||
"matrix-seshat": "^2.3.0",
|
||||
"keytar": "^5.6.0"
|
||||
},
|
||||
"build": {
|
||||
"appId": "im.riot.app",
|
||||
"electronVersion": "13.5.2",
|
||||
"files": [
|
||||
"package.json",
|
||||
{
|
||||
"from": ".hak/hakModules",
|
||||
"to": "node_modules"
|
||||
},
|
||||
"lib/**"
|
||||
],
|
||||
"extraResources": [
|
||||
{
|
||||
"from": "res/img",
|
||||
"to": "img"
|
||||
},
|
||||
"webapp.asar"
|
||||
],
|
||||
"linux": {
|
||||
"target": "deb",
|
||||
"category": "Network;InstantMessaging;Chat",
|
||||
"maintainer": "support@element.io",
|
||||
"desktop": {
|
||||
"StartupWMClass": "element"
|
||||
}
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"files": [],
|
||||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
"mac": {
|
||||
"category": "public.app-category.social-networking",
|
||||
"darkModeSupport": true
|
||||
},
|
||||
"scripts": {
|
||||
"i18n": "matrix-gen-i18n && yarn i18n:sort && yarn i18n:lint",
|
||||
"i18n:sort": "jq --sort-keys '.' src/i18n/strings/en_EN.json > src/i18n/strings/en_EN.json.tmp && mv src/i18n/strings/en_EN.json.tmp src/i18n/strings/en_EN.json",
|
||||
"i18n:lint": "prettier --write src/i18n/strings/ --ignore-path /dev/null",
|
||||
"i18n:diff": "cp src/i18n/strings/en_EN.json src/i18n/strings/en_EN_orig.json && yarn i18n && matrix-compare-i18n-files src/i18n/strings/en_EN_orig.json src/i18n/strings/en_EN.json",
|
||||
"mkdirs": "mkdirp packages deploys",
|
||||
"fetch": "yarn run mkdirs && ts-node scripts/fetch-package.ts",
|
||||
"asar-webapp": "asar p webapp webapp.asar",
|
||||
"start": "yarn run build:ts && yarn run build:res && electron .",
|
||||
"lint": "yarn lint:types && yarn lint:js",
|
||||
"lint:js": "yarn lint:js:src && yarn lint:js:test && yarn lint:js:scripts && yarn lint:js:hak",
|
||||
"lint:js:src": "eslint --max-warnings 0 src",
|
||||
"lint:js:test": "eslint --max-warnings 0 --config .eslintrc-test.js test",
|
||||
"lint:js:scripts": "eslint --max-warnings 0 --config .eslintrc-scripts.js scripts",
|
||||
"lint:js:hak": "eslint --max-warnings 0 --config .eslintrc-hak.js hak",
|
||||
"lint:js-fix": "yarn lint:js-fix:src &&yarn lint:js-fix:test && yarn lint:js-fix:scripts && yarn lint:js-fix:hak",
|
||||
"lint:js-fix:src": "eslint --fix --max-warnings 0 src",
|
||||
"lint:js-fix:test": "eslint --fix --max-warnings 0 --config .eslintrc-test.js test",
|
||||
"lint:js-fix:scripts": "eslint --fix --max-warnings 0 --config .eslintrc-scripts.js scripts",
|
||||
"lint:js-fix:hak": "eslint --fix --max-warnings 0 --config .eslintrc-hak.js hak",
|
||||
"lint:types": "yarn lint:types:src && yarn lint:types:test && yarn lint:types:scripts && yarn lint:types:hak",
|
||||
"lint:types:src": "tsc --noEmit",
|
||||
"lint:types:test": "tsc --noEmit -p test/tsconfig.json",
|
||||
"lint:types:scripts": "tsc --noEmit -p scripts/tsconfig.json",
|
||||
"lint:types:hak": "tsc --noEmit -p hak/tsconfig.json",
|
||||
"build:native": "yarn run hak",
|
||||
"build:native:universal": "yarn run hak --target x86_64-apple-darwin fetchandbuild && yarn run hak --target aarch64-apple-darwin fetchandbuild && yarn run hak --target x86_64-apple-darwin --target aarch64-apple-darwin copyandlink",
|
||||
"build:32": "yarn run build:ts && yarn run build:res && electron-builder --ia32",
|
||||
"build:64": "yarn run build:ts && yarn run build:res && electron-builder --x64",
|
||||
"build:universal": "yarn run build:ts && yarn run build:res && electron-builder --universal",
|
||||
"build": "yarn run build:ts && yarn run build:res && electron-builder",
|
||||
"build:ts": "tsc",
|
||||
"build:res": "ts-node scripts/copy-res.ts",
|
||||
"docker:setup": "docker build -t element-desktop-dockerbuild dockerbuild",
|
||||
"docker:build:native": "scripts/in-docker.sh yarn run hak",
|
||||
"docker:build": "scripts/in-docker.sh yarn run build",
|
||||
"docker:install": "scripts/in-docker.sh yarn install",
|
||||
"clean": "rimraf webapp.asar dist packages deploys lib",
|
||||
"hak": "ts-node scripts/hak/index.ts",
|
||||
"test": "jest"
|
||||
"win": {
|
||||
"target": {
|
||||
"target": "squirrel"
|
||||
},
|
||||
"sign": "scripts/electron_winSign"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sentry/electron": "^4.3.0",
|
||||
"auto-launch": "^5.0.5",
|
||||
"counterpart": "^0.18.6",
|
||||
"electron-clear-data": "^1.0.5",
|
||||
"electron-store": "^8.0.2",
|
||||
"electron-window-state": "^5.0.3",
|
||||
"minimist": "^1.2.6",
|
||||
"node-fetch": "^2",
|
||||
"png-to-ico": "^2.1.1",
|
||||
"uuid": "^9.0.0"
|
||||
"directories": {
|
||||
"output": "dist"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.18.10",
|
||||
"@babel/preset-env": "^7.18.10",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@electron/asar": "^3.2.3",
|
||||
"@electron/notarize": "^2.0.0",
|
||||
"@types/auto-launch": "^5.0.1",
|
||||
"@types/counterpart": "^0.18.1",
|
||||
"@types/detect-libc": "^1.0.0",
|
||||
"@types/jest": "^29.0.0",
|
||||
"@types/minimist": "^1.2.1",
|
||||
"@types/mkdirp": "^1.0.2",
|
||||
"@types/node": "16.18.52",
|
||||
"@types/pacote": "^11.1.1",
|
||||
"@types/tar": "^6.1.3",
|
||||
"@types/uuid": "^9.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "^5.42.0",
|
||||
"@typescript-eslint/parser": "^5.42.0",
|
||||
"allchange": "^1.0.6",
|
||||
"app-builder-lib": "24.6.5",
|
||||
"babel-jest": "^29.0.0",
|
||||
"chokidar": "^3.5.2",
|
||||
"detect-libc": "^1.0.3",
|
||||
"electron": "^26.2.1",
|
||||
"electron-builder": "24.6.4",
|
||||
"electron-builder-squirrel-windows": "24.6.5",
|
||||
"electron-devtools-installer": "^3.2.0",
|
||||
"eslint": "^8.26.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
"eslint-plugin-matrix-org": "^1.0.0",
|
||||
"eslint-plugin-unicorn": "^48.0.0",
|
||||
"expect-playwright": "^0.8.0",
|
||||
"find-npm-prefix": "^1.0.2",
|
||||
"fs-extra": "^11.0.0",
|
||||
"glob": "^10.0.0",
|
||||
"jest": "^29.0.0",
|
||||
"matrix-web-i18n": "^3.1.3",
|
||||
"mkdirp": "^3.0.0",
|
||||
"node-pre-gyp": "^0.17.0",
|
||||
"pacote": "^17.0.0",
|
||||
"playwright": "^1.25.0",
|
||||
"prettier": "^2.8.1",
|
||||
"rimraf": "^5.0.0",
|
||||
"tar": "^6.1.2",
|
||||
"ts-jest": "^29.0.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "5.1.6"
|
||||
},
|
||||
"hakDependencies": {
|
||||
"matrix-seshat": "^3.0.1",
|
||||
"keytar": "^7.9.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/node": "16.18.52"
|
||||
},
|
||||
"build": {
|
||||
"appId": "im.riot.app",
|
||||
"asarUnpack": "**/*.node",
|
||||
"files": [
|
||||
"package.json",
|
||||
{
|
||||
"from": ".hak/hakModules",
|
||||
"to": "node_modules"
|
||||
},
|
||||
"lib/**"
|
||||
],
|
||||
"extraResources": [
|
||||
{
|
||||
"from": "res/img",
|
||||
"to": "img"
|
||||
},
|
||||
"webapp.asar"
|
||||
],
|
||||
"linux": {
|
||||
"target": [
|
||||
"tar.gz",
|
||||
"deb"
|
||||
],
|
||||
"category": "Network;InstantMessaging;Chat",
|
||||
"maintainer": "support@element.io",
|
||||
"icon": "build/icons"
|
||||
},
|
||||
"deb": {
|
||||
"packageCategory": "net",
|
||||
"depends": [
|
||||
"libgtk-3-0",
|
||||
"libnotify4",
|
||||
"libnss3",
|
||||
"libxss1",
|
||||
"libxtst6",
|
||||
"xdg-utils",
|
||||
"libatspi2.0-0",
|
||||
"libuuid1",
|
||||
"libsecret-1-0",
|
||||
"libasound2",
|
||||
"libgbm1"
|
||||
],
|
||||
"recommends": [
|
||||
"libsqlcipher0",
|
||||
"element-io-archive-keyring"
|
||||
]
|
||||
},
|
||||
"mac": {
|
||||
"category": "public.app-category.social-networking",
|
||||
"darkModeSupport": true,
|
||||
"hardenedRuntime": true,
|
||||
"gatekeeperAssess": true,
|
||||
"entitlements": "./build/entitlements.mac.plist",
|
||||
"icon": "build/icons/icon.icns"
|
||||
},
|
||||
"win": {
|
||||
"target": [
|
||||
"squirrel"
|
||||
],
|
||||
"signingHashAlgorithms": [
|
||||
"sha256"
|
||||
],
|
||||
"icon": "build/icons/icon.ico"
|
||||
},
|
||||
"directories": {
|
||||
"output": "dist"
|
||||
},
|
||||
"protocols": [
|
||||
{
|
||||
"name": "element",
|
||||
"schemes": [
|
||||
"element"
|
||||
]
|
||||
}
|
||||
"afterPack": "scripts/electron_afterPack",
|
||||
"afterSign": "scripts/electron_afterSign",
|
||||
"protocols": [
|
||||
{
|
||||
"name": "element",
|
||||
"schemes": [
|
||||
"element"
|
||||
]
|
||||
},
|
||||
"jest": {
|
||||
"testEnvironment": "node",
|
||||
"testMatch": [
|
||||
"<rootDir>/test/**/*-test.[jt]s?(x)"
|
||||
],
|
||||
"setupFilesAfterEnv": [
|
||||
"expect-playwright"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Script to perform a release of element-desktop.
|
||||
#
|
||||
# Requires githib-changelog-generator; to install, do
|
||||
# pip install git+https://github.com/matrix-org/github-changelog-generator.git
|
||||
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
cd `dirname $0`
|
||||
|
||||
./node_modules/matrix-js-sdk/release.sh "$@"
|
||||
./node_modules/matrix-js-sdk/release.sh -n -z "$@"
|
||||
|
||||
19
scripts/@types/find-npm-prefix.d.ts
vendored
19
scripts/@types/find-npm-prefix.d.ts
vendored
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
Copyright 2022 New Vector 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 "find-npm-prefix" {
|
||||
export default function findPrefix(dir: string): Promise<string>;
|
||||
}
|
||||
20
scripts/@types/node-pre-gyp.d.ts
vendored
20
scripts/@types/node-pre-gyp.d.ts
vendored
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
Copyright 2022 New Vector 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 "node-pre-gyp/lib/util/versioning" {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
export function get_runtime_abi(runtime: string, version: string): string;
|
||||
}
|
||||
5
scripts/ci/install-deps.sh
Executable file
5
scripts/ci/install-deps.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -ex
|
||||
|
||||
yarn install --pure-lockfile $@
|
||||
121
scripts/copy-res.js
Executable file
121
scripts/copy-res.js
Executable file
@@ -0,0 +1,121 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// copies resources into the lib directory.
|
||||
|
||||
const parseArgs = require('minimist');
|
||||
const chokidar = require('chokidar');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
const argv = parseArgs(process.argv.slice(2), {});
|
||||
|
||||
const watch = argv.w;
|
||||
const verbose = argv.v;
|
||||
|
||||
function errCheck(err) {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
const I18N_BASE_PATH = "src/i18n/strings/";
|
||||
const INCLUDE_LANGS = fs.readdirSync(I18N_BASE_PATH).filter(fn => fn.endsWith(".json"));
|
||||
|
||||
// Ensure lib, lib/i18n and lib/i18n/strings all exist
|
||||
fs.mkdirSync('lib/i18n/strings', { recursive: true });
|
||||
|
||||
function genLangFile(file, dest) {
|
||||
let translations = {};
|
||||
[file].forEach(function(f) {
|
||||
if (fs.existsSync(f)) {
|
||||
try {
|
||||
Object.assign(
|
||||
translations,
|
||||
JSON.parse(fs.readFileSync(f).toString()),
|
||||
);
|
||||
} catch (e) {
|
||||
console.error("Failed: " + f, e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
translations = weblateToCounterpart(translations);
|
||||
|
||||
const json = JSON.stringify(translations, null, 4);
|
||||
const filename = path.basename(file);
|
||||
|
||||
fs.writeFileSync(dest + filename, json);
|
||||
if (verbose) {
|
||||
console.log("Generated language file: " + filename);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert translation key from weblate format
|
||||
* (which only supports a single level) to counterpart
|
||||
* which requires object values for 'count' translations.
|
||||
*
|
||||
* eg.
|
||||
* "there are %(count)s badgers|one": "a badger",
|
||||
* "there are %(count)s badgers|other": "%(count)s badgers"
|
||||
* becomes
|
||||
* "there are %(count)s badgers": {
|
||||
* "one": "a badger",
|
||||
* "other": "%(count)s badgers"
|
||||
* }
|
||||
*/
|
||||
function weblateToCounterpart(inTrs) {
|
||||
const outTrs = {};
|
||||
|
||||
for (const key of Object.keys(inTrs)) {
|
||||
const keyParts = key.split('|', 2);
|
||||
if (keyParts.length === 2) {
|
||||
let obj = outTrs[keyParts[0]];
|
||||
if (obj === undefined) {
|
||||
obj = {};
|
||||
outTrs[keyParts[0]] = obj;
|
||||
}
|
||||
obj[keyParts[1]] = inTrs[key];
|
||||
} else {
|
||||
outTrs[key] = inTrs[key];
|
||||
}
|
||||
}
|
||||
|
||||
return outTrs;
|
||||
}
|
||||
|
||||
/*
|
||||
watch the input files for a given language,
|
||||
regenerate the file, and regenerating languages.json with the new filename
|
||||
*/
|
||||
function watchLanguage(file, dest) {
|
||||
// XXX: Use a debounce because for some reason if we read the language
|
||||
// file immediately after the FS event is received, the file contents
|
||||
// appears empty. Possibly https://github.com/nodejs/node/issues/6112
|
||||
let makeLangDebouncer;
|
||||
const makeLang = () => {
|
||||
if (makeLangDebouncer) {
|
||||
clearTimeout(makeLangDebouncer);
|
||||
}
|
||||
makeLangDebouncer = setTimeout(() => {
|
||||
genLangFile(file, dest);
|
||||
}, 500);
|
||||
};
|
||||
|
||||
chokidar.watch(file)
|
||||
.on('add', makeLang)
|
||||
.on('change', makeLang)
|
||||
.on('error', errCheck);
|
||||
}
|
||||
|
||||
// language resources
|
||||
const I18N_DEST = "lib/i18n/strings/";
|
||||
INCLUDE_LANGS.forEach((file) => {
|
||||
genLangFile(I18N_BASE_PATH + file, I18N_DEST);
|
||||
}, {});
|
||||
|
||||
if (watch) {
|
||||
INCLUDE_LANGS.forEach(file => watchLanguage(I18N_BASE_PATH + file, I18N_DEST));
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
#!/usr/bin/env -S npx ts-node
|
||||
|
||||
// copies resources into the lib directory.
|
||||
|
||||
import parseArgs from "minimist";
|
||||
import * as chokidar from "chokidar";
|
||||
import * as path from "path";
|
||||
import * as fs from "fs";
|
||||
|
||||
const argv = parseArgs(process.argv.slice(2), {});
|
||||
|
||||
const watch = argv.w;
|
||||
const verbose = argv.v;
|
||||
|
||||
function errCheck(err?: Error): void {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
const I18N_BASE_PATH = "src/i18n/strings/";
|
||||
const INCLUDE_LANGS = fs.readdirSync(I18N_BASE_PATH).filter((fn) => fn.endsWith(".json"));
|
||||
|
||||
// Ensure lib, lib/i18n and lib/i18n/strings all exist
|
||||
fs.mkdirSync("lib/i18n/strings", { recursive: true });
|
||||
|
||||
type Translations = Record<string, Record<string, string> | string>;
|
||||
|
||||
function genLangFile(file: string, dest: string): void {
|
||||
const translations: Translations = {};
|
||||
[file].forEach(function (f) {
|
||||
if (fs.existsSync(f)) {
|
||||
try {
|
||||
Object.assign(translations, JSON.parse(fs.readFileSync(f).toString()));
|
||||
} catch (e) {
|
||||
console.error("Failed: " + f, e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const json = JSON.stringify(translations, null, 4);
|
||||
const filename = path.basename(file);
|
||||
|
||||
fs.writeFileSync(dest + filename, json);
|
||||
if (verbose) {
|
||||
console.log("Generated language file: " + filename);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
watch the input files for a given language,
|
||||
regenerate the file, and regenerating languages.json with the new filename
|
||||
*/
|
||||
function watchLanguage(file: string, dest: string): void {
|
||||
// XXX: Use a debounce because for some reason if we read the language
|
||||
// file immediately after the FS event is received, the file contents
|
||||
// appears empty. Possibly https://github.com/nodejs/node/issues/6112
|
||||
let makeLangDebouncer: NodeJS.Timeout | undefined;
|
||||
const makeLang = (): void => {
|
||||
if (makeLangDebouncer) {
|
||||
clearTimeout(makeLangDebouncer);
|
||||
}
|
||||
makeLangDebouncer = setTimeout(() => {
|
||||
genLangFile(file, dest);
|
||||
}, 500);
|
||||
};
|
||||
|
||||
chokidar.watch(file).on("add", makeLang).on("change", makeLang).on("error", errCheck);
|
||||
}
|
||||
|
||||
// language resources
|
||||
const I18N_DEST = "lib/i18n/strings/";
|
||||
INCLUDE_LANGS.forEach((file): void => {
|
||||
genLangFile(I18N_BASE_PATH + file, I18N_DEST);
|
||||
}, {});
|
||||
|
||||
if (watch) {
|
||||
INCLUDE_LANGS.forEach((file) => watchLanguage(I18N_BASE_PATH + file, I18N_DEST));
|
||||
}
|
||||
15
scripts/electron_afterPack.js
Normal file
15
scripts/electron_afterPack.js
Normal file
@@ -0,0 +1,15 @@
|
||||
const fsProm = require('fs').promises;
|
||||
const path = require('path');
|
||||
|
||||
exports.default = async function(context) {
|
||||
const { electronPlatformName, appOutDir } = context;
|
||||
|
||||
// Squirrel windows will try to relaunch the app using an executable of the same name as
|
||||
// before in the new version, so will fail if the executable is now called something else.
|
||||
// We add a fake Riot.exe that it can run which runs the real one.
|
||||
// This also gets signed automatically, presumably because electron-build just looks for all
|
||||
// exe files and signs them all...
|
||||
if (electronPlatformName === 'win32') {
|
||||
await fsProm.copyFile('build/rebrand_stub/rebrand_stub.exe', path.join(appOutDir, "Riot.exe"));
|
||||
}
|
||||
};
|
||||
29
scripts/electron_afterSign.js
Normal file
29
scripts/electron_afterSign.js
Normal file
@@ -0,0 +1,29 @@
|
||||
const { notarize } = require('electron-notarize');
|
||||
|
||||
exports.default = async function(context) {
|
||||
const { electronPlatformName, appOutDir } = context;
|
||||
const appId = context.packager.info.appInfo.id;
|
||||
|
||||
if (electronPlatformName === 'darwin') {
|
||||
const appName = context.packager.appInfo.productFilename;
|
||||
// We get the password from keychain. The keychain stores
|
||||
// user IDs too, but apparently altool can't get the user ID
|
||||
// from the keychain, so we need to get it from the environment.
|
||||
const userId = process.env.NOTARIZE_APPLE_ID;
|
||||
if (userId === undefined) {
|
||||
console.log("*************************************");
|
||||
console.log("* NOTARIZE_APPLE_ID is not set. *");
|
||||
console.log("* This build will NOT be notarised. *");
|
||||
console.log("*************************************");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Notarising macOS app. This may be some time.");
|
||||
return await notarize({
|
||||
appBundleId: appId,
|
||||
appPath: `${appOutDir}/${appName}.app`,
|
||||
appleId: userId,
|
||||
appleIdPassword: '@keychain:NOTARIZE_CREDS',
|
||||
});
|
||||
}
|
||||
};
|
||||
74
scripts/electron_winSign.js
Normal file
74
scripts/electron_winSign.js
Normal file
@@ -0,0 +1,74 @@
|
||||
const { execFile } = require('child_process');
|
||||
|
||||
// Loosely based on computeSignToolArgs from app-builder-lib/src/codeSign/windowsCodeSign.ts
|
||||
function computeSignToolArgs(options, keyContainer) {
|
||||
const args = [];
|
||||
|
||||
if (process.env.ELECTRON_BUILDER_OFFLINE !== "true") {
|
||||
const timestampingServiceUrl = options.options.timeStampServer || "http://timestamp.digicert.com";
|
||||
args.push(
|
||||
options.isNest || options.hash === "sha256" ? "/tr" : "/t",
|
||||
options.isNest || options.hash === "sha256" ? (
|
||||
options.options.rfc3161TimeStampServer || "http://timestamp.comodoca.com/rfc3161"
|
||||
) : timestampingServiceUrl,
|
||||
);
|
||||
}
|
||||
|
||||
args.push('/kc', keyContainer);
|
||||
// To use the hardware token (this should probably be less hardcoded)
|
||||
args.push('/csp', 'eToken Base Cryptographic Provider');
|
||||
// The certificate file. Somehow this appears to be the only way to specify
|
||||
// the cert that works. If you specify the subject name or hash, it will
|
||||
// say it can't associate the private key to the certificate.
|
||||
// TODO: Find a way to pass this through from the electron-builder config
|
||||
// so we don't have to hard-code this here
|
||||
// fwiw https://stackoverflow.com/questions/17927895/automate-extended-validation-ev-code-signing
|
||||
// is about the most useful resource on automating code signing...
|
||||
args.push('/f', 'element.io\\New_Vector_Ltd.pem');
|
||||
|
||||
if (options.hash !== "sha1") {
|
||||
args.push("/fd", options.hash);
|
||||
if (process.env.ELECTRON_BUILDER_OFFLINE !== "true") {
|
||||
args.push("/td", "sha256");
|
||||
}
|
||||
}
|
||||
|
||||
// msi does not support dual-signing
|
||||
if (options.isNest) {
|
||||
args.push("/as");
|
||||
}
|
||||
|
||||
// https://github.com/electron-userland/electron-builder/issues/2875#issuecomment-387233610
|
||||
args.push("/debug");
|
||||
// must be last argument
|
||||
args.push(options.path);
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
exports.default = async function(options) {
|
||||
const keyContainer = process.env.SIGNING_KEY_CONTAINER;
|
||||
if (keyContainer === undefined) {
|
||||
console.warn(
|
||||
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" +
|
||||
"! Skipping Windows signing. !\n" +
|
||||
"! SIGNING_KEY_CONTAINER not defined. !\n" +
|
||||
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const args = ['sign'].concat(computeSignToolArgs(options, keyContainer));
|
||||
|
||||
execFile('signtool', args, {}, (error, stdout) => {
|
||||
if (error) {
|
||||
console.error("signtool failed with code " + error);
|
||||
reject("signtool failed with code " + error);
|
||||
console.log(stdout);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
291
scripts/fetch-package.js
Executable file
291
scripts/fetch-package.js
Executable file
@@ -0,0 +1,291 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const process = require('process');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const fsPromises = require('fs').promises;
|
||||
const childProcess = require('child_process');
|
||||
const tar = require('tar');
|
||||
const asar = require('asar');
|
||||
const needle = require('needle');
|
||||
|
||||
const riotDesktopPackageJson = require('../package.json');
|
||||
|
||||
const PUB_KEY_URL = "https://packages.riot.im/element-release-key.asc";
|
||||
const PACKAGE_URL_PREFIX = "https://github.com/vector-im/element-web/releases/download/";
|
||||
const ASAR_PATH = 'webapp.asar';
|
||||
|
||||
const { setPackageVersion } = require('./set-version.js');
|
||||
|
||||
async function getLatestDevelopUrl(bkToken) {
|
||||
const buildsResult = await needle('get',
|
||||
"https://api.buildkite.com/v2/organizations/matrix-dot-org/pipelines/element-web/builds",
|
||||
{
|
||||
branch: 'develop',
|
||||
state: 'passed',
|
||||
per_page: 1,
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
authorization: "Bearer " + bkToken,
|
||||
},
|
||||
},
|
||||
);
|
||||
const latestBuild = buildsResult.body[0];
|
||||
console.log("Latest build is " + latestBuild.number);
|
||||
let artifactUrl;
|
||||
for (const job of latestBuild.jobs) {
|
||||
// Strip any colon-form emoji from the build name
|
||||
if (job.name && job.name.replace(/:\w*:\s*/, '') === 'Package') {
|
||||
artifactUrl = job.artifacts_url;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (artifactUrl === undefined) {
|
||||
throw new Error("Couldn't find artifact URL - has the name of the package job changed?");
|
||||
}
|
||||
|
||||
const artifactsResult = await needle('get', artifactUrl, {},
|
||||
{
|
||||
headers: {
|
||||
authorization: "Bearer " + bkToken,
|
||||
},
|
||||
},
|
||||
);
|
||||
let dlUrl;
|
||||
let dlFilename;
|
||||
for (const artifact of artifactsResult.body) {
|
||||
if (artifact.filename && /^element-.*\.tar.gz$/.test(artifact.filename)) {
|
||||
dlUrl = artifact.download_url;
|
||||
dlFilename = artifact.filename;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dlUrl === undefined) {
|
||||
throw new Error("Couldn't find artifact download URL - has the artifact filename changed?");
|
||||
}
|
||||
console.log("Fetching artifact URL...");
|
||||
const dlResult = await needle('get', dlUrl, {},
|
||||
{
|
||||
headers: {
|
||||
authorization: "Bearer " + bkToken,
|
||||
},
|
||||
// This URL will give us a Location header, but will also give us
|
||||
// a JSON object with the direct URL. We'll take the URL and pass it
|
||||
// back, then we can easily support specifying a URL directly.
|
||||
follow_max: 0,
|
||||
},
|
||||
);
|
||||
return [dlFilename, dlResult.body.url];
|
||||
}
|
||||
|
||||
async function downloadToFile(url, filename) {
|
||||
console.log("Downloading " + url + "...");
|
||||
|
||||
try {
|
||||
await needle('get', url, null,
|
||||
{
|
||||
follow_max: 5,
|
||||
output: filename,
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
try {
|
||||
await fsPromises.unlink(filename);
|
||||
} catch (_) {}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
async function verifyFile(filename) {
|
||||
return new Promise((resolve, reject) => {
|
||||
childProcess.execFile('gpg', ['--verify', filename + '.asc', filename], (error) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
let verify = true;
|
||||
let importkey = false;
|
||||
let pkgDir = 'packages';
|
||||
let deployDir = 'deploys';
|
||||
let cfgDir;
|
||||
let targetVersion;
|
||||
let filename;
|
||||
let url;
|
||||
let setVersion = false;
|
||||
|
||||
while (process.argv.length > 2) {
|
||||
switch (process.argv[2]) {
|
||||
case '--noverify':
|
||||
verify = false;
|
||||
break;
|
||||
case '--importkey':
|
||||
importkey = true;
|
||||
break;
|
||||
case '--packages':
|
||||
process.argv.shift();
|
||||
pkgDir = process.argv[2];
|
||||
break;
|
||||
case '--deploys':
|
||||
process.argv.shift();
|
||||
deployDir = process.argv[2];
|
||||
break;
|
||||
case '--cfgdir':
|
||||
case '-d':
|
||||
process.argv.shift();
|
||||
cfgDir = process.argv[2];
|
||||
break;
|
||||
default:
|
||||
targetVersion = process.argv[2];
|
||||
}
|
||||
process.argv.shift();
|
||||
}
|
||||
|
||||
if (targetVersion === undefined) {
|
||||
targetVersion = 'v' + riotDesktopPackageJson.version;
|
||||
filename = 'element-' + targetVersion + '.tar.gz';
|
||||
url = PACKAGE_URL_PREFIX + targetVersion + '/' + filename;
|
||||
} else if (targetVersion === 'develop') {
|
||||
const buildKiteApiKey = process.env.BUILDKITE_API_KEY;
|
||||
if (buildKiteApiKey === undefined) {
|
||||
console.log("Set BUILDKITE_API_KEY to fetch latest develop version");
|
||||
console.log(
|
||||
"Sorry - Buildkite's API requires authentication to access builds, " +
|
||||
"even if those builds are accessible on the web with no auth.",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
[filename, url] = await getLatestDevelopUrl(buildKiteApiKey);
|
||||
verify = false; // develop builds aren't signed
|
||||
} else {
|
||||
filename = 'element-' + targetVersion + '.tar.gz';
|
||||
url = PACKAGE_URL_PREFIX + targetVersion + '/' + filename;
|
||||
setVersion = true;
|
||||
}
|
||||
|
||||
const haveGpg = await new Promise((resolve) => {
|
||||
childProcess.execFile('gpg', ['--version'], (error) => {
|
||||
resolve(!error);
|
||||
});
|
||||
});
|
||||
|
||||
if (importkey) {
|
||||
if (!haveGpg) {
|
||||
console.log("Can't import key without working GPG binary: install GPG and try again");
|
||||
return 1;
|
||||
}
|
||||
|
||||
await new Promise((resolve) => {
|
||||
const gpgProc = childProcess.execFile('gpg', ['--import'], (error) => {
|
||||
if (error) {
|
||||
console.log("Failed to import key", error);
|
||||
} else {
|
||||
console.log("Key imported!");
|
||||
}
|
||||
resolve(!error);
|
||||
});
|
||||
needle.get(PUB_KEY_URL).pipe(gpgProc.stdin);
|
||||
});
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cfgDir === undefined) {
|
||||
console.log("No config directory set");
|
||||
console.log("Specify a config directory with --cfgdir or -d");
|
||||
console.log("To build with no config (and no auto-update), pass the empty string (-d '')");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (verify && !haveGpg) {
|
||||
console.log("No working GPG binary: install GPG or pass --noverify to skip verification");
|
||||
return 1;
|
||||
}
|
||||
|
||||
let haveDeploy = false;
|
||||
const expectedDeployDir = path.join(deployDir, path.basename(filename).replace(/\.tar\.gz/, ''));
|
||||
try {
|
||||
await fs.opendir(expectedDeployDir);
|
||||
console.log(expectedDeployDir + "already exists");
|
||||
haveDeploy = true;
|
||||
} catch (e) {
|
||||
}
|
||||
|
||||
if (!haveDeploy) {
|
||||
const outPath = path.join(pkgDir, filename);
|
||||
try {
|
||||
await fsPromises.stat(outPath);
|
||||
console.log("Already have " + filename + ": not redownloading");
|
||||
} catch (e) {
|
||||
try {
|
||||
await downloadToFile(url, outPath);
|
||||
} catch (e) {
|
||||
console.log("Failed to download " + url, e);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (verify) {
|
||||
try {
|
||||
await fsPromises.stat(outPath+'.asc');
|
||||
console.log("Already have " + filename + ".asc: not redownloading");
|
||||
} catch (e) {
|
||||
try {
|
||||
await downloadToFile(url + '.asc', outPath + '.asc');
|
||||
} catch (e) {
|
||||
console.log("Failed to download " + url, e);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await verifyFile(outPath);
|
||||
console.log(outPath + " downloaded and verified");
|
||||
} catch (e) {
|
||||
console.log("Signature verification failed!", e);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
console.log(outPath + " downloaded but NOT verified");
|
||||
}
|
||||
|
||||
await tar.x({
|
||||
file: outPath,
|
||||
cwd: deployDir,
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
await fsPromises.stat(ASAR_PATH);
|
||||
console.log(ASAR_PATH + " already present: removing");
|
||||
await fsPromises.unlink(ASAR_PATH);
|
||||
} catch (e) {
|
||||
}
|
||||
|
||||
if (cfgDir.length) {
|
||||
const configJsonSource = path.join(cfgDir, 'config.json');
|
||||
const configJsonDest = path.join(expectedDeployDir, 'config.json');
|
||||
console.log(configJsonSource + ' -> ' + configJsonDest);
|
||||
await fsPromises.copyFile(configJsonSource, configJsonDest);
|
||||
} else {
|
||||
console.log("Skipping config file");
|
||||
}
|
||||
|
||||
console.log("Pack " + expectedDeployDir + " -> " + ASAR_PATH);
|
||||
await asar.createPackage(expectedDeployDir, ASAR_PATH);
|
||||
|
||||
if (setVersion) {
|
||||
const semVer = targetVersion.slice(1);
|
||||
console.log("Updating version to " + semVer);
|
||||
await setPackageVersion(semVer);
|
||||
}
|
||||
|
||||
console.log("Done!");
|
||||
}
|
||||
|
||||
main().then((ret) => process.exit(ret)).catch(e => process.exit(1));
|
||||
@@ -1,237 +0,0 @@
|
||||
#!/usr/bin/env -S npx ts-node --resolveJsonModule
|
||||
|
||||
import * as path from "path";
|
||||
import { createWriteStream, promises as fs } from "fs";
|
||||
import * as childProcess from "child_process";
|
||||
import tar from "tar";
|
||||
import * as asar from "@electron/asar";
|
||||
import fetch from "node-fetch";
|
||||
import { promises as stream } from "stream";
|
||||
|
||||
import riotDesktopPackageJson from "../package.json";
|
||||
import { setPackageVersion } from "./set-version";
|
||||
|
||||
const PUB_KEY_URL = "https://packages.riot.im/element-release-key.asc";
|
||||
const PACKAGE_URL_PREFIX = "https://github.com/vector-im/element-web/releases/download/";
|
||||
const DEVELOP_TGZ_URL = "https://develop.element.io/develop.tar.gz";
|
||||
const ASAR_PATH = "webapp.asar";
|
||||
|
||||
async function downloadToFile(url: string, filename: string): Promise<void> {
|
||||
console.log("Downloading " + url + "...");
|
||||
|
||||
try {
|
||||
const resp = await fetch(url);
|
||||
if (!resp.ok) throw new Error(`unexpected response ${resp.statusText}`);
|
||||
if (!resp.body) throw new Error(`unexpected response has no body ${resp.statusText}`);
|
||||
await stream.pipeline(resp.body, createWriteStream(filename));
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
try {
|
||||
await fs.unlink(filename);
|
||||
} catch (_) {}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
async function verifyFile(filename: string): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
childProcess.execFile("gpg", ["--verify", filename + ".asc", filename], (error) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function main(): Promise<number | undefined> {
|
||||
let verify = true;
|
||||
let importkey = false;
|
||||
let pkgDir = "packages";
|
||||
let deployDir = "deploys";
|
||||
let cfgDir: string | undefined;
|
||||
let targetVersion: string | undefined;
|
||||
let filename: string | undefined;
|
||||
let url: string | undefined;
|
||||
let setVersion = false;
|
||||
|
||||
while (process.argv.length > 2) {
|
||||
switch (process.argv[2]) {
|
||||
case "--noverify":
|
||||
verify = false;
|
||||
break;
|
||||
case "--importkey":
|
||||
importkey = true;
|
||||
break;
|
||||
case "--packages":
|
||||
process.argv.shift();
|
||||
pkgDir = process.argv[2];
|
||||
break;
|
||||
case "--deploys":
|
||||
process.argv.shift();
|
||||
deployDir = process.argv[2];
|
||||
break;
|
||||
case "--cfgdir":
|
||||
case "-d":
|
||||
process.argv.shift();
|
||||
cfgDir = process.argv[2];
|
||||
break;
|
||||
default:
|
||||
targetVersion = process.argv[2];
|
||||
}
|
||||
process.argv.shift();
|
||||
}
|
||||
|
||||
if (targetVersion === undefined) {
|
||||
targetVersion = "v" + riotDesktopPackageJson.version;
|
||||
} else if (targetVersion !== "develop") {
|
||||
setVersion = true; // version was specified
|
||||
}
|
||||
|
||||
if (targetVersion === "develop") {
|
||||
filename = "develop.tar.gz";
|
||||
url = DEVELOP_TGZ_URL;
|
||||
verify = false; // develop builds aren't signed
|
||||
} else if (targetVersion.includes("://")) {
|
||||
filename = targetVersion.substring(targetVersion.lastIndexOf("/") + 1);
|
||||
url = targetVersion;
|
||||
verify = false; // manually verified
|
||||
} else {
|
||||
filename = `element-${targetVersion}.tar.gz`;
|
||||
url = PACKAGE_URL_PREFIX + targetVersion + "/" + filename;
|
||||
}
|
||||
|
||||
const haveGpg = await new Promise<boolean>((resolve) => {
|
||||
childProcess.execFile("gpg", ["--version"], (error) => {
|
||||
resolve(!error);
|
||||
});
|
||||
});
|
||||
|
||||
if (importkey) {
|
||||
if (!haveGpg) {
|
||||
console.log("Can't import key without working GPG binary: install GPG and try again");
|
||||
return 1;
|
||||
}
|
||||
|
||||
await new Promise<boolean>((resolve) => {
|
||||
const gpgProc = childProcess.execFile("gpg", ["--import"], (error) => {
|
||||
if (error) {
|
||||
console.log("Failed to import key", error);
|
||||
} else {
|
||||
console.log("Key imported!");
|
||||
}
|
||||
resolve(!error);
|
||||
});
|
||||
fetch(PUB_KEY_URL).then((resp) => {
|
||||
stream.pipeline(resp.body, gpgProc.stdin!);
|
||||
});
|
||||
});
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cfgDir === undefined) {
|
||||
console.log("No config directory set");
|
||||
console.log("Specify a config directory with --cfgdir or -d");
|
||||
console.log("To build with no config (and no auto-update), pass the empty string (-d '')");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (verify && !haveGpg) {
|
||||
console.log("No working GPG binary: install GPG or pass --noverify to skip verification");
|
||||
return 1;
|
||||
}
|
||||
|
||||
let haveDeploy = false;
|
||||
let expectedDeployDir = path.join(deployDir, path.basename(filename).replace(/\.tar\.gz/, ""));
|
||||
try {
|
||||
await fs.opendir(expectedDeployDir);
|
||||
console.log(expectedDeployDir + "already exists");
|
||||
haveDeploy = true;
|
||||
} catch (e) {}
|
||||
|
||||
if (!haveDeploy) {
|
||||
const outPath = path.join(pkgDir, filename);
|
||||
try {
|
||||
await fs.stat(outPath);
|
||||
console.log("Already have " + filename + ": not redownloading");
|
||||
} catch (e) {
|
||||
try {
|
||||
await downloadToFile(url, outPath);
|
||||
} catch (e) {
|
||||
console.log("Failed to download " + url, e);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (verify) {
|
||||
try {
|
||||
await fs.stat(outPath + ".asc");
|
||||
console.log("Already have " + filename + ".asc: not redownloading");
|
||||
} catch (e) {
|
||||
try {
|
||||
await downloadToFile(url + ".asc", outPath + ".asc");
|
||||
} catch (e) {
|
||||
console.log("Failed to download " + url, e);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await verifyFile(outPath);
|
||||
console.log(outPath + " downloaded and verified");
|
||||
} catch (e) {
|
||||
console.log("Signature verification failed!", e);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
console.log(outPath + " downloaded but NOT verified");
|
||||
}
|
||||
|
||||
await tar.x({
|
||||
file: outPath,
|
||||
cwd: deployDir,
|
||||
onentry: (entry) => {
|
||||
// Find the appropriate extraction path, only needed for `develop` where the dir name is unknown
|
||||
if (entry.type === "Directory" && !path.join(deployDir, entry.path).startsWith(expectedDeployDir)) {
|
||||
expectedDeployDir = path.join(deployDir, entry.path);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
await fs.stat(ASAR_PATH);
|
||||
console.log(ASAR_PATH + " already present: removing");
|
||||
await fs.unlink(ASAR_PATH);
|
||||
} catch (e) {}
|
||||
|
||||
if (cfgDir.length) {
|
||||
const configJsonSource = path.join(cfgDir, "config.json");
|
||||
const configJsonDest = path.join(expectedDeployDir, "config.json");
|
||||
console.log(configJsonSource + " -> " + configJsonDest);
|
||||
await fs.copyFile(configJsonSource, configJsonDest);
|
||||
} else {
|
||||
console.log("Skipping config file");
|
||||
}
|
||||
|
||||
console.log("Pack " + expectedDeployDir + " -> " + ASAR_PATH);
|
||||
await asar.createPackage(expectedDeployDir, ASAR_PATH);
|
||||
|
||||
if (setVersion) {
|
||||
const semVer = (await fs.readFile(path.join(expectedDeployDir, "version"), "utf-8")).trim();
|
||||
console.log("Updating version to " + semVer);
|
||||
await setPackageVersion(semVer);
|
||||
}
|
||||
|
||||
console.log("Done!");
|
||||
}
|
||||
|
||||
main()
|
||||
.then((ret) => {
|
||||
process.exit(ret);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -17,8 +17,7 @@ clone() {
|
||||
if [ -n "$branch" ]
|
||||
then
|
||||
echo "Trying to use $org/$repo#$branch"
|
||||
# Disable auth prompts: https://serverfault.com/a/665959
|
||||
GIT_TERMINAL_PROMPT=0 git clone https://github.com/$org/$repo.git $repo --branch "$branch" --depth 1 && exit 0
|
||||
git clone git://github.com/$org/$repo.git $repo --branch "$branch" --depth 1 && exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
#!/usr/bin/env -S npx ts-node
|
||||
|
||||
/**
|
||||
* Script to generate electron-builder.json config files for builds which don't match package.json, e.g. nightlies
|
||||
* This script has different outputs depending on your os platform.
|
||||
*
|
||||
* On Windows:
|
||||
* Prefixes the nightly version with `0.0.1-nightly.` as it breaks if it is not semver
|
||||
*
|
||||
* On macOS:
|
||||
* Passes --notarytool-team-id to build.mac.notarize.notarize if specified
|
||||
*
|
||||
* On Linux:
|
||||
* Replaces spaces in the product name with dashes as spaces in paths can cause issues
|
||||
* Passes --deb-custom-control to build.deb.fpm if specified
|
||||
* Removes libsqlcipher0 recommended dependency if env SQLCIPHER_BUNDLED is asserted.
|
||||
*/
|
||||
|
||||
import parseArgs from "minimist";
|
||||
import fsProm from "fs/promises";
|
||||
import * as os from "os";
|
||||
import { Configuration } from "app-builder-lib";
|
||||
|
||||
const ELECTRON_BUILDER_CFG_FILE = "electron-builder.json";
|
||||
|
||||
const NIGHTLY_APP_ID = "im.riot.nightly";
|
||||
const NIGHTLY_APP_NAME = "element-desktop-nightly";
|
||||
const NIGHTLY_DEB_NAME = "element-nightly";
|
||||
|
||||
const argv = parseArgs<{
|
||||
"nightly"?: string;
|
||||
"signtool-thumbprint"?: string;
|
||||
"signtool-subject-name"?: string;
|
||||
"notarytool-team-id"?: string;
|
||||
"deb-changelog"?: string;
|
||||
}>(process.argv.slice(2), {
|
||||
string: ["nightly", "deb-changelog", "signtool-thumbprint", "signtool-subject-name", "notarytool-team-id"],
|
||||
});
|
||||
|
||||
type DeepWriteable<T> = { -readonly [P in keyof T]: DeepWriteable<T[P]> };
|
||||
|
||||
interface PackageBuild extends DeepWriteable<Omit<Configuration, "extraMetadata">> {
|
||||
extraMetadata?: {
|
||||
productName?: string;
|
||||
name?: string;
|
||||
version?: string;
|
||||
description?: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface Package {
|
||||
build: PackageBuild;
|
||||
productName: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
async function main(): Promise<number | void> {
|
||||
// Electron builder doesn't overlay with the config in package.json, so load it here
|
||||
const pkg: Package = JSON.parse(await fsProm.readFile("package.json", "utf8"));
|
||||
|
||||
const cfg: PackageBuild = {
|
||||
...pkg.build,
|
||||
extraMetadata: {
|
||||
productName: pkg.productName,
|
||||
description: pkg.description,
|
||||
},
|
||||
};
|
||||
|
||||
if (!cfg.deb!.fpm) cfg.deb!.fpm = [];
|
||||
|
||||
if (argv.nightly) {
|
||||
cfg.appId = NIGHTLY_APP_ID;
|
||||
cfg.extraMetadata!.productName += " Nightly";
|
||||
cfg.extraMetadata!.name = NIGHTLY_APP_NAME;
|
||||
cfg.extraMetadata!.description += " (nightly unstable build)";
|
||||
cfg.deb!.fpm!.push("--name", NIGHTLY_DEB_NAME);
|
||||
|
||||
let version = argv.nightly;
|
||||
if (os.platform() === "win32") {
|
||||
// The windows packager relies on parsing this as semver, so we have to make it look like one.
|
||||
// This will give our update packages really stupid names, but we probably can't change that either
|
||||
// because squirrel windows parses them for the version too. We don't really care: nobody sees them.
|
||||
// We just give the installer a static name, so you'll just see this in the 'about' dialog.
|
||||
// Turns out if you use 0.0.0 here it makes Squirrel windows crash, so we use 0.0.1.
|
||||
version = "0.0.1-nightly." + version;
|
||||
}
|
||||
cfg.extraMetadata!.version = version;
|
||||
} else {
|
||||
cfg.deb!.fpm!.push("--deb-field", "Replaces: riot-desktop (<< 1.7.0), riot-web (<< 1.7.0)");
|
||||
cfg.deb!.fpm!.push("--deb-field", "Breaks: riot-desktop (<< 1.7.0), riot-web (<< 1.7.0)");
|
||||
}
|
||||
|
||||
if (argv["signtool-thumbprint"] && argv["signtool-subject-name"]) {
|
||||
cfg.win!.certificateSubjectName = argv["signtool-subject-name"];
|
||||
cfg.win!.certificateSha1 = argv["signtool-thumbprint"];
|
||||
}
|
||||
|
||||
if (argv["notarytool-team-id"]) {
|
||||
cfg.mac!.notarize = {
|
||||
teamId: argv["notarytool-team-id"],
|
||||
};
|
||||
}
|
||||
|
||||
if (os.platform() === "linux") {
|
||||
// Electron crashes on debian if there's a space in the path.
|
||||
// https://github.com/vector-im/element-web/issues/13171
|
||||
cfg.extraMetadata!.productName = cfg.extraMetadata!.productName!.replace(/ /g, "-");
|
||||
|
||||
if (argv["deb-changelog"]) {
|
||||
cfg.deb!.fpm!.push(`--deb-changelog=${argv["deb-changelog"]}`);
|
||||
}
|
||||
|
||||
if (process.env.SQLCIPHER_BUNDLED) {
|
||||
// Remove sqlcipher dependency when using bundled
|
||||
cfg.deb!.recommends = cfg.deb!.recommends?.filter((d) => d !== "libsqlcipher0");
|
||||
}
|
||||
}
|
||||
|
||||
await fsProm.writeFile(ELECTRON_BUILDER_CFG_FILE, JSON.stringify(cfg, null, 4));
|
||||
}
|
||||
|
||||
main()
|
||||
.then((ret) => {
|
||||
process.exit(ret!);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -1,41 +0,0 @@
|
||||
#!/usr/bin/env -S npx ts-node
|
||||
|
||||
/**
|
||||
* Script to generate incremental Nightly build versions, based on the latest Nightly build version of that kind.
|
||||
* The version format is YYYYMMDDNN where NN is in case we need to do multiple versions in a day.
|
||||
*
|
||||
* NB. on windows, squirrel will try to parse the version number parts, including this string, into 32-bit integers,
|
||||
* which is fine as long as we only add two digits to the end...
|
||||
*/
|
||||
|
||||
import parseArgs from "minimist";
|
||||
|
||||
const argv = parseArgs<{
|
||||
latest?: string;
|
||||
}>(process.argv.slice(2), {
|
||||
string: ["latest"],
|
||||
});
|
||||
|
||||
function parseVersion(version: string): [Date, number] {
|
||||
const year = parseInt(version.slice(0, 4), 10);
|
||||
const month = parseInt(version.slice(4, 6), 10);
|
||||
const day = parseInt(version.slice(6, 8), 10);
|
||||
const num = parseInt(version.slice(8, 10), 10);
|
||||
return [new Date(year, month - 1, day), num];
|
||||
}
|
||||
|
||||
const [latestDate, latestNum] = argv.latest ? parseVersion(argv.latest) : [];
|
||||
|
||||
const now = new Date();
|
||||
const month = (now.getMonth() + 1).toString().padStart(2, "0");
|
||||
const date = now.getDate().toString().padStart(2, "0");
|
||||
let buildNum = 1;
|
||||
if (latestDate && new Date(latestDate).getDate().toString().padStart(2, "0") === date) {
|
||||
buildNum = latestNum! + 1;
|
||||
}
|
||||
|
||||
if (buildNum > 99) {
|
||||
throw new Error("Maximum number of Nightlies exceeded on this day.");
|
||||
}
|
||||
|
||||
console.log(now.getFullYear() + month + date + buildNum.toString().padStart(2, "0"));
|
||||
@@ -1,25 +0,0 @@
|
||||
#!/usr/bin/env -S npx ts-node
|
||||
|
||||
/*
|
||||
* Checks for the presence of a webapp, inspects its version and prints it
|
||||
*/
|
||||
|
||||
import { versionFromAsar } from "./set-version";
|
||||
|
||||
async function main(): Promise<number> {
|
||||
const version = await versionFromAsar();
|
||||
console.log(version);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main()
|
||||
.then((ret) => {
|
||||
process.exit(ret);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
@@ -1,40 +1,40 @@
|
||||
# hak
|
||||
hak
|
||||
===
|
||||
|
||||
This tool builds native dependencies for element-desktop. Here follows some very minimal
|
||||
documentation for it.
|
||||
|
||||
Goals:
|
||||
|
||||
- Must build compiled native node modules in a shippable state
|
||||
(ie. only dynamically linked against libraries that will be on the
|
||||
target system, all unnecessary files removed).
|
||||
- Must be able to build any native module, no matter what build system
|
||||
it uses (electron-rebuild is supposed to do this job but only works
|
||||
for modules that use gyp).
|
||||
* Must build compiled native node modules in a shippable state
|
||||
(ie. only dynamically linked against libraries that will be on the
|
||||
target system, all unnecessary files removed).
|
||||
* Must be able to build any native module, no matter what build system
|
||||
it uses (electron-rebuild is supposed to do this job but only works
|
||||
for modules that use gyp).
|
||||
|
||||
It's also loosely designed to be a general tool and agnostic to what it's
|
||||
actually building. It's used here to build modules for the electron app
|
||||
but should work equally well for building modules for normal node.
|
||||
|
||||
# Running
|
||||
|
||||
Running
|
||||
=======
|
||||
Hak is invoked with a command and a dependency, eg. `yarn run hak fetch matrix-seshat`.
|
||||
If no dependencies are given, hak runs the command on all dependencies.
|
||||
|
||||
# Files
|
||||
|
||||
Files
|
||||
=====
|
||||
There are a lot of files involved:
|
||||
|
||||
- scripts/hak/... - The tool itself
|
||||
- hak/[dependency] - Files provided by the app that tell hak how to build each of its native dependencies.
|
||||
Contains a hak.json file and also some script files, each of which must be referenced in hak.json.
|
||||
- .hak/ - Files generated by hak in the course of doing its job. Includes the dependency module itself and
|
||||
any of the native dependency's native dependencies.
|
||||
- .hak/[dependency]/build - An extracted copy of the dependency's node module used to build it.
|
||||
- .hak/[dependency]/out - Another extracted copy of the dependency, this one contains only what will be shipped.
|
||||
|
||||
# Workings
|
||||
* scripts/hak/... - The tool itself
|
||||
* hak/[dependency] - Files provided by the app that tell hak how to build each of its native dependencies.
|
||||
Contains a hak.json file and also some script files, each of which must be referenced in hak.json.
|
||||
* .hak/ - Files generated by hak in the course of doing its job. Includes the dependency module itself and
|
||||
any of the native dependency's native dependencies.
|
||||
* .hak/[dependency]/build - An extracted copy of the dependency's node module used to build it.
|
||||
* .hak/[dependency]/out - Another extracted copy of the dependency, this one contains only what will be shipped.
|
||||
|
||||
Workings
|
||||
========
|
||||
Hak works around native node modules that try to fetch or build their native component in
|
||||
the npm 'install' phase - modules that do this will typically end up with native components
|
||||
targeted to the build platform and the node that npm/yarn is using, which is no good for an
|
||||
@@ -49,33 +49,33 @@ This also means that the dependencies cannot be listed in `dependencies` or
|
||||
try to fetch their native parts. Instead, they are listed in `hakDependencies` which
|
||||
hak reads to install them for you.
|
||||
|
||||
Hak will _not_ install dependencies for the copy of the module it links into your
|
||||
Hak will *not* install dependencies for the copy of the module it links into your
|
||||
project, so if your native module has javascript dependencies that are actually needed at
|
||||
runtime (and not just to fetch / build the native parts), it won't work.
|
||||
|
||||
Hak will generate a `.yarnrc` in the project directory to set the link directory to its
|
||||
own in the .hak directory (unless one already exists, in which case this is your problem).
|
||||
|
||||
# Lifecycle
|
||||
|
||||
Lifecycle
|
||||
=========
|
||||
Hak is divided into lifecycle stages, in order:
|
||||
* fetch - Download and extract the source of the dependency
|
||||
* link - Link the copy of the dependency into your node_modules directory
|
||||
* fetchDeps - Fetch & extract any native dependencies required to build the module.
|
||||
* build - The Good Stuff. Configure and build any native dependencies, then the module itself.
|
||||
* copy - Copy the built artifact from the module build directory to the module output directory.
|
||||
|
||||
- fetch - Download and extract the source of the dependency
|
||||
- link - Link the copy of the dependency into your node_modules directory
|
||||
- build - The Good Stuff. Configure and build any native dependencies, then the module itself.
|
||||
- copy - Copy the built artifact from the module build directory to the module output directory.
|
||||
|
||||
# hak.json
|
||||
|
||||
hak.json
|
||||
========
|
||||
The scripts section contains scripts used for lifecycle stages that need them (fetch, fetchDeps, build).
|
||||
It also contains 'prune' and 'copy' which are globs of files to delete from the output module directory
|
||||
and copy over from the module build directory to the output module directory, respectively.
|
||||
|
||||
# Shortcomings
|
||||
|
||||
Shortcomings
|
||||
============
|
||||
Hak doesn't know about dependencies between lifecycle stages, ie. it doesn't know that you need to
|
||||
'fetch' and 'fetchDeps' before you can 'build', etc. You get to run each individually, and remember
|
||||
the right order.
|
||||
|
||||
There is also a _lot_ of duplication in the command execution: we should abstract away
|
||||
There is also a *lot* of duplication in the command execution: we should abstract away
|
||||
some of the boilerplate required to run commands & so forth.
|
||||
|
||||
@@ -14,9 +14,8 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { DependencyInfo } from "./dep";
|
||||
import HakEnv from "./hakEnv";
|
||||
|
||||
export default async function build(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
|
||||
async function build(hakEnv, moduleInfo) {
|
||||
await moduleInfo.scripts.build(hakEnv, moduleInfo);
|
||||
}
|
||||
|
||||
module.exports = build;
|
||||
@@ -14,11 +14,10 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { DependencyInfo } from "./dep";
|
||||
import HakEnv from "./hakEnv";
|
||||
|
||||
export default async function check(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
|
||||
async function check(hakEnv, moduleInfo) {
|
||||
if (moduleInfo.scripts.check) {
|
||||
await moduleInfo.scripts.check(hakEnv, moduleInfo);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = check;
|
||||
53
scripts/hak/clean.js
Normal file
53
scripts/hak/clean.js
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
const path = require('path');
|
||||
|
||||
const rimraf = require('rimraf');
|
||||
|
||||
async function clean(hakEnv, moduleInfo) {
|
||||
await new Promise((resolve, reject) => {
|
||||
rimraf(moduleInfo.moduleDotHakDir, (err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
rimraf(path.join(hakEnv.dotHakDir, 'links', moduleInfo.name), (err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
rimraf(path.join(hakEnv.projectRoot, 'node_modules', moduleInfo.name), (err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = clean;
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
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 path from "path";
|
||||
import { rimraf } from "rimraf";
|
||||
|
||||
import { DependencyInfo } from "./dep";
|
||||
import HakEnv from "./hakEnv";
|
||||
|
||||
export default async function clean(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
|
||||
await rimraf(moduleInfo.moduleDotHakDir);
|
||||
await rimraf(path.join(hakEnv.dotHakDir, "links", moduleInfo.name));
|
||||
await rimraf(path.join(hakEnv.projectRoot, "node_modules", moduleInfo.name));
|
||||
}
|
||||
@@ -14,26 +14,27 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import path from "path";
|
||||
import fsProm from "fs/promises";
|
||||
import childProcess from "child_process";
|
||||
import { rimraf } from "rimraf";
|
||||
import { glob } from "glob";
|
||||
import { mkdirp } from "mkdirp";
|
||||
const path = require('path');
|
||||
const fsProm = require('fs').promises;
|
||||
const childProcess = require('child_process');
|
||||
|
||||
import HakEnv from "./hakEnv";
|
||||
import { DependencyInfo } from "./dep";
|
||||
const rimraf = require('rimraf');
|
||||
const glob = require('glob');
|
||||
const mkdirp = require('mkdirp');
|
||||
|
||||
export default async function copy(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
|
||||
async function copy(hakEnv, moduleInfo) {
|
||||
if (moduleInfo.cfg.prune) {
|
||||
console.log("Removing " + moduleInfo.cfg.prune + " from " + moduleInfo.moduleOutDir);
|
||||
// rimraf doesn't have a 'cwd' option: it always uses process.cwd()
|
||||
// (and if you set glob.cwd it just breaks because it can't find the files)
|
||||
const oldCwd = process.cwd();
|
||||
try {
|
||||
await mkdirp(moduleInfo.moduleOutDir);
|
||||
process.chdir(moduleInfo.moduleOutDir);
|
||||
await rimraf(moduleInfo.cfg.prune);
|
||||
await new Promise((resolve, reject) => {
|
||||
rimraf(moduleInfo.cfg.prune, {}, err => {
|
||||
err ? reject(err) : resolve();
|
||||
});
|
||||
});
|
||||
} finally {
|
||||
process.chdir(oldCwd);
|
||||
}
|
||||
@@ -43,35 +44,47 @@ export default async function copy(hakEnv: HakEnv, moduleInfo: DependencyInfo):
|
||||
// If there are multiple moduleBuildDirs, singular moduleBuildDir
|
||||
// is the same as moduleBuildDirs[0], so we're just listing the contents
|
||||
// of the first one.
|
||||
const files = await glob(moduleInfo.cfg.copy, {
|
||||
cwd: moduleInfo.moduleBuildDir,
|
||||
const files = await new Promise(async (resolve, reject) => {
|
||||
glob(moduleInfo.cfg.copy, {
|
||||
nosort: true,
|
||||
silent: true,
|
||||
cwd: moduleInfo.moduleBuildDir,
|
||||
}, (err, files) => {
|
||||
err ? reject(err) : resolve(files);
|
||||
});
|
||||
});
|
||||
|
||||
if (moduleInfo.moduleBuildDirs.length > 1) {
|
||||
if (!hakEnv.isMac()) {
|
||||
console.error(
|
||||
"You asked me to copy multiple targets but I've only been taught " + "how to do that on macOS.",
|
||||
"You asked me to copy multiple targets but I've only been taught " +
|
||||
"how to do that on macOS.",
|
||||
);
|
||||
throw new Error("Can't copy multiple targets on this platform");
|
||||
}
|
||||
|
||||
for (const f of files) {
|
||||
const components = moduleInfo.moduleBuildDirs.map((dir) => path.join(dir, f));
|
||||
const components = moduleInfo.moduleBuildDirs.map(dir => path.join(dir, f));
|
||||
const dst = path.join(moduleInfo.moduleOutDir, f);
|
||||
|
||||
await mkdirp(path.dirname(dst));
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
childProcess.execFile("lipo", ["-create", "-output", dst, ...components], (err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
await new Promise((resolve, reject) => {
|
||||
childProcess.execFile('lipo',
|
||||
['-create', '-output', dst, ...components], (err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
console.log("Copying files from " + moduleInfo.moduleBuildDir + " to " + moduleInfo.moduleOutDir);
|
||||
console.log(
|
||||
"Copying files from " +
|
||||
moduleInfo.moduleBuildDir + " to " + moduleInfo.moduleOutDir,
|
||||
);
|
||||
for (const f of files) {
|
||||
console.log("\t" + f);
|
||||
const src = path.join(moduleInfo.moduleBuildDir, f);
|
||||
@@ -83,3 +96,5 @@ export default async function copy(hakEnv: HakEnv, moduleInfo: DependencyInfo):
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = copy;
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
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 HakEnv from "./hakEnv";
|
||||
|
||||
export interface DependencyInfo {
|
||||
name: string;
|
||||
version: string;
|
||||
cfg: Record<string, any>;
|
||||
moduleHakDir: string;
|
||||
moduleDotHakDir: string;
|
||||
moduleTargetDotHakDir: string;
|
||||
moduleBuildDir: string;
|
||||
moduleBuildDirs: string[];
|
||||
moduleOutDir: string;
|
||||
nodeModuleBinDir: string;
|
||||
depPrefix: string;
|
||||
scripts: Record<string, (hakEnv: HakEnv, moduleInfo: DependencyInfo) => Promise<void>>;
|
||||
}
|
||||
@@ -14,14 +14,12 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import fsProm from "fs/promises";
|
||||
import childProcess from "child_process";
|
||||
import pacote from "pacote";
|
||||
const fsProm = require('fs').promises;
|
||||
const childProcess = require('child_process');
|
||||
|
||||
import HakEnv from "./hakEnv";
|
||||
import { DependencyInfo } from "./dep";
|
||||
const pacote = require('pacote');
|
||||
|
||||
export default async function fetch(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
|
||||
async function fetch(hakEnv, moduleInfo) {
|
||||
let haveModuleBuildDir;
|
||||
try {
|
||||
const stats = await fsProm.stat(moduleInfo.moduleBuildDir);
|
||||
@@ -40,12 +38,16 @@ export default async function fetch(hakEnv: HakEnv, moduleInfo: DependencyInfo):
|
||||
});
|
||||
|
||||
console.log("Running yarn install in " + moduleInfo.moduleBuildDir);
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const proc = childProcess.spawn(hakEnv.isWin() ? "yarn.cmd" : "yarn", ["install", "--ignore-scripts"], {
|
||||
stdio: "inherit",
|
||||
cwd: moduleInfo.moduleBuildDir,
|
||||
});
|
||||
proc.on("exit", (code) => {
|
||||
await new Promise((resolve, reject) => {
|
||||
const proc = childProcess.spawn(
|
||||
hakEnv.isWin() ? 'yarn.cmd' : 'yarn',
|
||||
['install', '--ignore-scripts'],
|
||||
{
|
||||
stdio: 'inherit',
|
||||
cwd: moduleInfo.moduleBuildDir,
|
||||
},
|
||||
);
|
||||
proc.on('exit', code => {
|
||||
code ? reject(code) : resolve();
|
||||
});
|
||||
});
|
||||
@@ -64,3 +66,5 @@ export default async function fetch(hakEnv: HakEnv, moduleInfo: DependencyInfo):
|
||||
packumentCache,
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = fetch;
|
||||
@@ -14,14 +14,13 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { mkdirp } from "mkdirp";
|
||||
const mkdirp = require('mkdirp');
|
||||
|
||||
import { DependencyInfo } from "./dep";
|
||||
import HakEnv from "./hakEnv";
|
||||
|
||||
export default async function fetchDeps(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
|
||||
async function fetchDeps(hakEnv, moduleInfo) {
|
||||
await mkdirp(moduleInfo.moduleDotHakDir);
|
||||
if (moduleInfo.scripts.fetchDeps) {
|
||||
await moduleInfo.scripts.fetchDeps(hakEnv, moduleInfo);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = fetchDeps;
|
||||
122
scripts/hak/hakEnv.js
Normal file
122
scripts/hak/hakEnv.js
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
Copyright 2020-2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
|
||||
const nodePreGypVersioning = require('node-pre-gyp/lib/util/versioning');
|
||||
const { TARGETS, getHost, isHostId } = require('./target');
|
||||
|
||||
function getElectronVersion(packageJson) {
|
||||
// should we pick the version of an installed electron
|
||||
// dependency, and if so, before or after electronVersion?
|
||||
if (packageJson.build && packageJson.build.electronVersion) {
|
||||
return packageJson.build.electronVersion;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getRuntime(packageJson) {
|
||||
const electronVersion = getElectronVersion(packageJson);
|
||||
return electronVersion ? 'electron' : 'node-webkit';
|
||||
}
|
||||
|
||||
function getRuntimeVersion(packageJson) {
|
||||
const electronVersion = getElectronVersion(packageJson);
|
||||
if (electronVersion) {
|
||||
return electronVersion;
|
||||
} else {
|
||||
return process.version.substr(1);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = class HakEnv {
|
||||
constructor(prefix, packageJson, targetId) {
|
||||
let target;
|
||||
if (targetId) {
|
||||
target = TARGETS[targetId];
|
||||
} else {
|
||||
target = getHost();
|
||||
}
|
||||
|
||||
if (!target) {
|
||||
throw new Error(`Unknown target ${targetId}!`);
|
||||
}
|
||||
|
||||
Object.assign(this, {
|
||||
// what we're targeting
|
||||
runtime: getRuntime(packageJson),
|
||||
runtimeVersion: getRuntimeVersion(packageJson),
|
||||
target,
|
||||
|
||||
// paths
|
||||
projectRoot: prefix,
|
||||
dotHakDir: path.join(prefix, '.hak'),
|
||||
});
|
||||
}
|
||||
|
||||
getRuntimeAbi() {
|
||||
return nodePreGypVersioning.get_runtime_abi(
|
||||
this.runtime,
|
||||
this.runtimeVersion,
|
||||
);
|
||||
}
|
||||
|
||||
// {node_abi}-{platform}-{arch}
|
||||
getNodeTriple() {
|
||||
return this.getRuntimeAbi() + '-' + this.target.platform + '-' + this.target.arch;
|
||||
}
|
||||
|
||||
getTargetId() {
|
||||
return this.target.id;
|
||||
}
|
||||
|
||||
isWin() {
|
||||
return this.target.platform === 'win32';
|
||||
}
|
||||
|
||||
isMac() {
|
||||
return this.target.platform === 'darwin';
|
||||
}
|
||||
|
||||
isLinux() {
|
||||
return this.target.platform === 'linux';
|
||||
}
|
||||
|
||||
getTargetArch() {
|
||||
return this.target.arch;
|
||||
}
|
||||
|
||||
isHost() {
|
||||
return isHostId(this.target.id);
|
||||
}
|
||||
|
||||
makeGypEnv() {
|
||||
return Object.assign({}, process.env, {
|
||||
npm_config_arch: this.target.arch,
|
||||
npm_config_target_arch: this.target.arch,
|
||||
npm_config_disturl: 'https://atom.io/download/electron',
|
||||
npm_config_runtime: this.runtime,
|
||||
npm_config_target: this.runtimeVersion,
|
||||
npm_config_build_from_source: true,
|
||||
npm_config_devdir: path.join(os.homedir(), ".electron-gyp"),
|
||||
});
|
||||
}
|
||||
|
||||
getNodeModuleBin(name) {
|
||||
return path.join(this.projectRoot, 'node_modules', '.bin', name);
|
||||
}
|
||||
};
|
||||
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
Copyright 2020-2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
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 path from "path";
|
||||
import os from "os";
|
||||
import nodePreGypVersioning from "node-pre-gyp/lib/util/versioning";
|
||||
import { getElectronVersion } from "app-builder-lib/out/electron/electronVersion";
|
||||
|
||||
import { Arch, Target, TARGETS, getHost, isHostId, TargetId } from "./target";
|
||||
|
||||
async function getRuntime(projectRoot: string): Promise<string> {
|
||||
const electronVersion = await getElectronVersion(projectRoot);
|
||||
return electronVersion ? "electron" : "node-webkit";
|
||||
}
|
||||
|
||||
async function getRuntimeVersion(projectRoot: string): Promise<string> {
|
||||
const electronVersion = await getElectronVersion(projectRoot);
|
||||
if (electronVersion) {
|
||||
return electronVersion;
|
||||
} else {
|
||||
return process.version.substr(1);
|
||||
}
|
||||
}
|
||||
|
||||
export default class HakEnv {
|
||||
public readonly target: Target;
|
||||
public runtime?: string;
|
||||
public runtimeVersion?: string;
|
||||
public dotHakDir: string;
|
||||
|
||||
public constructor(public readonly projectRoot: string, targetId: TargetId | null) {
|
||||
const target = targetId ? TARGETS[targetId] : getHost();
|
||||
|
||||
if (!target) {
|
||||
throw new Error(`Unknown target ${targetId}!`);
|
||||
}
|
||||
this.target = target;
|
||||
this.dotHakDir = path.join(this.projectRoot, ".hak");
|
||||
}
|
||||
|
||||
public async init(): Promise<void> {
|
||||
this.runtime = await getRuntime(this.projectRoot);
|
||||
this.runtimeVersion = await getRuntimeVersion(this.projectRoot);
|
||||
}
|
||||
|
||||
public getRuntimeAbi(): string {
|
||||
return nodePreGypVersioning.get_runtime_abi(this.runtime!, this.runtimeVersion!);
|
||||
}
|
||||
|
||||
// {node_abi}-{platform}-{arch}
|
||||
public getNodeTriple(): string {
|
||||
return this.getRuntimeAbi() + "-" + this.target.platform + "-" + this.target.arch;
|
||||
}
|
||||
|
||||
public getTargetId(): TargetId {
|
||||
return this.target.id;
|
||||
}
|
||||
|
||||
public isWin(): boolean {
|
||||
return this.target.platform === "win32";
|
||||
}
|
||||
|
||||
public isMac(): boolean {
|
||||
return this.target.platform === "darwin";
|
||||
}
|
||||
|
||||
public isLinux(): boolean {
|
||||
return this.target.platform === "linux";
|
||||
}
|
||||
|
||||
public isFreeBSD(): boolean {
|
||||
return this.target.platform === "freebsd";
|
||||
}
|
||||
|
||||
public getTargetArch(): Arch {
|
||||
return this.target.arch;
|
||||
}
|
||||
|
||||
public isHost(): boolean {
|
||||
return isHostId(this.target.id);
|
||||
}
|
||||
|
||||
public makeGypEnv(): Record<string, string | undefined> {
|
||||
return Object.assign({}, process.env, {
|
||||
npm_config_arch: this.target.arch,
|
||||
npm_config_target_arch: this.target.arch,
|
||||
npm_config_disturl: "https://electronjs.org/headers",
|
||||
npm_config_runtime: this.runtime,
|
||||
npm_config_target: this.runtimeVersion,
|
||||
npm_config_build_from_source: true,
|
||||
npm_config_devdir: path.join(os.homedir(), ".electron-gyp"),
|
||||
});
|
||||
}
|
||||
|
||||
public wantsStaticSqlCipher(): boolean {
|
||||
return !(this.isLinux() || this.isFreeBSD()) || process.env.SQLCIPHER_BUNDLED == "1";
|
||||
}
|
||||
}
|
||||
@@ -14,29 +14,43 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import path from "path";
|
||||
import findNpmPrefix from "find-npm-prefix";
|
||||
const path = require('path');
|
||||
|
||||
import HakEnv from "./hakEnv";
|
||||
import { TargetId } from "./target";
|
||||
import { DependencyInfo } from "./dep";
|
||||
const findNpmPrefix = require('find-npm-prefix');
|
||||
|
||||
const GENERALCOMMANDS = ["target"];
|
||||
const HakEnv = require('./hakEnv');
|
||||
|
||||
const GENERALCOMMANDS = [
|
||||
'target',
|
||||
];
|
||||
|
||||
// These can only be run on specific modules
|
||||
const MODULECOMMANDS = ["check", "fetch", "link", "build", "copy", "clean"];
|
||||
const MODULECOMMANDS = [
|
||||
'check',
|
||||
'fetch',
|
||||
'link',
|
||||
'fetchDeps',
|
||||
'build',
|
||||
'copy',
|
||||
'clean',
|
||||
];
|
||||
|
||||
// Shortcuts for multiple commands at once (useful for building universal binaries
|
||||
// because you can run the fetch/fetchDeps/build for each arch and then copy/link once)
|
||||
const METACOMMANDS: Record<string, string[]> = {
|
||||
fetchandbuild: ["check", "fetch", "build"],
|
||||
copyandlink: ["copy", "link"],
|
||||
const METACOMMANDS = {
|
||||
'fetchandbuild': ['check', 'fetch', 'fetchDeps', 'build'],
|
||||
'copyandlink': ['copy', 'link'],
|
||||
};
|
||||
|
||||
// Scripts valid in a hak.json 'scripts' section
|
||||
const HAKSCRIPTS = ["check", "fetch", "build"];
|
||||
const HAKSCRIPTS = [
|
||||
'check',
|
||||
'fetch',
|
||||
'fetchDeps',
|
||||
'build',
|
||||
];
|
||||
|
||||
async function main(): Promise<void> {
|
||||
async function main() {
|
||||
const prefix = await findNpmPrefix(process.cwd());
|
||||
let packageJson;
|
||||
try {
|
||||
@@ -46,37 +60,33 @@ async function main(): Promise<void> {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const targetIds: TargetId[] = [];
|
||||
const targetIds = [];
|
||||
// Apply `--target <target>` option if specified
|
||||
// Can be specified multiple times for the copy command to bundle
|
||||
// multiple archs into a single universal output module)
|
||||
for (;;) {
|
||||
// eslint-disable-line no-constant-condition
|
||||
const targetIndex = process.argv.indexOf("--target");
|
||||
while (true) { // eslint-disable-line no-constant-condition
|
||||
const targetIndex = process.argv.indexOf('--target');
|
||||
if (targetIndex === -1) break;
|
||||
|
||||
if (targetIndex + 1 >= process.argv.length) {
|
||||
if ((targetIndex + 1) >= process.argv.length) {
|
||||
console.error("--target option specified without a target");
|
||||
process.exit(1);
|
||||
}
|
||||
// Extract target ID and remove from args
|
||||
targetIds.push(process.argv.splice(targetIndex, 2)[1] as TargetId);
|
||||
targetIds.push(process.argv.splice(targetIndex, 2)[1]);
|
||||
}
|
||||
|
||||
const hakEnvs = targetIds.map((tid) => new HakEnv(prefix, tid));
|
||||
if (hakEnvs.length == 0) hakEnvs.push(new HakEnv(prefix, null));
|
||||
for (const h of hakEnvs) {
|
||||
await h.init();
|
||||
}
|
||||
const hakEnvs = targetIds.map(tid => new HakEnv(prefix, packageJson, tid));
|
||||
if (hakEnvs.length == 0) hakEnvs.push(new HakEnv(prefix, packageJson, null));
|
||||
const hakEnv = hakEnvs[0];
|
||||
|
||||
const deps: Record<string, DependencyInfo> = {};
|
||||
const deps = {};
|
||||
|
||||
const hakDepsCfg = packageJson.hakDependencies || {};
|
||||
|
||||
for (const dep of Object.keys(hakDepsCfg)) {
|
||||
const hakJsonPath = path.join(prefix, "hak", dep, "hak.json");
|
||||
let hakJson: Record<string, any>;
|
||||
const hakJsonPath = path.join(prefix, 'hak', dep, 'hak.json');
|
||||
let hakJson;
|
||||
try {
|
||||
hakJson = await require(hakJsonPath);
|
||||
} catch (e) {
|
||||
@@ -88,39 +98,34 @@ async function main(): Promise<void> {
|
||||
name: dep,
|
||||
version: hakDepsCfg[dep],
|
||||
cfg: hakJson,
|
||||
moduleHakDir: path.join(prefix, "hak", dep),
|
||||
moduleHakDir: path.join(prefix, 'hak', dep),
|
||||
moduleDotHakDir: path.join(hakEnv.dotHakDir, dep),
|
||||
moduleTargetDotHakDir: path.join(hakEnv.dotHakDir, dep, hakEnv.getTargetId()),
|
||||
moduleBuildDir: path.join(hakEnv.dotHakDir, dep, hakEnv.getTargetId(), "build"),
|
||||
moduleBuildDirs: hakEnvs.map((h) => path.join(h.dotHakDir, dep, h.getTargetId(), "build")),
|
||||
moduleOutDir: path.join(hakEnv.dotHakDir, "hakModules", dep),
|
||||
nodeModuleBinDir: path.join(hakEnv.dotHakDir, dep, hakEnv.getTargetId(), "build", "node_modules", ".bin"),
|
||||
depPrefix: path.join(hakEnv.dotHakDir, dep, hakEnv.getTargetId(), "opt"),
|
||||
moduleBuildDir: path.join(hakEnv.dotHakDir, dep, hakEnv.getTargetId(), 'build'),
|
||||
moduleBuildDirs: hakEnvs.map(h => path.join(h.dotHakDir, dep, h.getTargetId(), 'build')),
|
||||
moduleOutDir: path.join(hakEnv.dotHakDir, 'hakModules', dep),
|
||||
nodeModuleBinDir: path.join(hakEnv.dotHakDir, dep, hakEnv.getTargetId(), 'build', 'node_modules', '.bin'),
|
||||
depPrefix: path.join(hakEnv.dotHakDir, dep, hakEnv.getTargetId(), 'opt'),
|
||||
scripts: {},
|
||||
};
|
||||
|
||||
for (const s of HAKSCRIPTS) {
|
||||
if (hakJson.scripts && hakJson.scripts[s]) {
|
||||
const scriptModule = await import(path.join(prefix, "hak", dep, hakJson.scripts[s]));
|
||||
if (scriptModule.__esModule) {
|
||||
deps[dep].scripts[s] = scriptModule.default;
|
||||
} else {
|
||||
deps[dep].scripts[s] = scriptModule;
|
||||
}
|
||||
deps[dep].scripts[s] = require(path.join(prefix, 'hak', dep, hakJson.scripts[s]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let cmds: string[];
|
||||
let cmds;
|
||||
if (process.argv.length < 3) {
|
||||
cmds = ["check", "fetch", "build", "copy", "link"];
|
||||
cmds = ['check', 'fetch', 'fetchDeps', 'build', 'copy', 'link'];
|
||||
} else if (METACOMMANDS[process.argv[2]]) {
|
||||
cmds = METACOMMANDS[process.argv[2]];
|
||||
} else {
|
||||
cmds = [process.argv[2]];
|
||||
}
|
||||
|
||||
if (hakEnvs.length > 1 && cmds.some((c) => !["copy", "link"].includes(c))) {
|
||||
if (hakEnvs.length > 1 && cmds.some(c => !['copy', 'link'].includes(c))) {
|
||||
// We allow link here too for convenience because it's completely arch independent
|
||||
console.error("Multiple targets only supported with the copy command");
|
||||
return;
|
||||
@@ -131,7 +136,7 @@ async function main(): Promise<void> {
|
||||
|
||||
for (const cmd of cmds) {
|
||||
if (GENERALCOMMANDS.includes(cmd)) {
|
||||
if (cmd === "target") {
|
||||
if (cmd === 'target') {
|
||||
console.log(hakEnv.getNodeTriple());
|
||||
}
|
||||
return;
|
||||
@@ -146,12 +151,15 @@ async function main(): Promise<void> {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const cmdFunc = (await import("./" + cmd)).default;
|
||||
const cmdFunc = require('./' + cmd);
|
||||
|
||||
for (const mod of modules) {
|
||||
const depInfo = deps[mod];
|
||||
if (depInfo === undefined) {
|
||||
console.log("Module " + mod + " not found - is it in hakDependencies " + "in your package.json?");
|
||||
console.log(
|
||||
"Module " + mod + " not found - is it in hakDependencies " +
|
||||
"in your package.json?",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
console.log("hak " + cmd + ": " + mod);
|
||||
@@ -160,7 +168,7 @@ async function main(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
main().catch(err => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -14,16 +14,13 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import path from "path";
|
||||
import os from "os";
|
||||
import fsProm from "fs/promises";
|
||||
import childProcess from "child_process";
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
const fsProm = require('fs').promises;
|
||||
const childProcess = require('child_process');
|
||||
|
||||
import HakEnv from "./hakEnv";
|
||||
import { DependencyInfo } from "./dep";
|
||||
|
||||
export default async function link(hakEnv: HakEnv, moduleInfo: DependencyInfo): Promise<void> {
|
||||
const yarnrc = path.join(hakEnv.projectRoot, ".yarnrc");
|
||||
async function link(hakEnv, moduleInfo) {
|
||||
const yarnrc = path.join(hakEnv.projectRoot, '.yarnrc');
|
||||
// this is fairly terrible but it's reasonably clunky to either parse a yarnrc
|
||||
// properly or get yarn to do it, so this will probably suffice for now.
|
||||
// We just check to see if there is a local .yarnrc at all, and assume that
|
||||
@@ -43,29 +40,31 @@ export default async function link(hakEnv: HakEnv, moduleInfo: DependencyInfo):
|
||||
// (ie. Windows absolute paths) but strings in quotes get parsed as
|
||||
// JSON so need to be valid JSON encoded strings (ie. have the
|
||||
// backslashes escaped). JSON.stringify will add quotes and escape.
|
||||
"--link-folder " + JSON.stringify(path.join(hakEnv.dotHakDir, "links")) + os.EOL,
|
||||
'--link-folder ' + JSON.stringify(path.join(hakEnv.dotHakDir, 'links')) + os.EOL,
|
||||
);
|
||||
}
|
||||
|
||||
const yarnCmd = "yarn" + (hakEnv.isWin() ? ".cmd" : "");
|
||||
const yarnCmd = 'yarn' + (hakEnv.isWin() ? '.cmd' : '');
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const proc = childProcess.spawn(yarnCmd, ["link"], {
|
||||
await new Promise((resolve, reject) => {
|
||||
const proc = childProcess.spawn(yarnCmd, ['link'], {
|
||||
cwd: moduleInfo.moduleOutDir,
|
||||
stdio: "inherit",
|
||||
stdio: 'inherit',
|
||||
});
|
||||
proc.on("exit", (code) => {
|
||||
proc.on('exit', code => {
|
||||
code ? reject(code) : resolve();
|
||||
});
|
||||
});
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const proc = childProcess.spawn(yarnCmd, ["link", moduleInfo.name], {
|
||||
await new Promise((resolve, reject) => {
|
||||
const proc = childProcess.spawn(yarnCmd, ['link', moduleInfo.name], {
|
||||
cwd: hakEnv.projectRoot,
|
||||
stdio: "inherit",
|
||||
stdio: 'inherit',
|
||||
});
|
||||
proc.on("exit", (code) => {
|
||||
proc.on('exit', code => {
|
||||
code ? reject(code) : resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = link;
|
||||
82
scripts/hak/target.js
Normal file
82
scripts/hak/target.js
Normal file
@@ -0,0 +1,82 @@
|
||||
"use strict";
|
||||
/*
|
||||
Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* THIS FILE IS GENERATED, NOT MEANT FOR EDITING DIRECTLY
|
||||
* The original source is `target.ts` in the `element-builder` repo. You can
|
||||
* edit it over there, run `yarn build`, and paste the changes here. It is
|
||||
* currently assumed this file will rarely change, so a spearate package is not
|
||||
* yet warranted.
|
||||
*/
|
||||
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.isHost = exports.isHostId = exports.getHost = exports.ENABLED_TARGETS = exports.TARGETS = void 0;
|
||||
const aarch64AppleDarwin = {
|
||||
id: 'aarch64-apple-darwin',
|
||||
platform: 'darwin',
|
||||
arch: 'arm64',
|
||||
};
|
||||
const i686PcWindowsMsvc = {
|
||||
id: 'i686-pc-windows-msvc',
|
||||
platform: 'win32',
|
||||
arch: 'ia32',
|
||||
vcVarsArch: 'x86',
|
||||
};
|
||||
const x8664PcWindowsMsvc = {
|
||||
id: 'x86_64-pc-windows-msvc',
|
||||
platform: 'win32',
|
||||
arch: 'x64',
|
||||
vcVarsArch: 'amd64',
|
||||
};
|
||||
const x8664AppleDarwin = {
|
||||
id: 'x86_64-apple-darwin',
|
||||
platform: 'darwin',
|
||||
arch: 'x64',
|
||||
};
|
||||
const x8664UnknownLinuxGnu = {
|
||||
id: 'x86_64-unknown-linux-gnu',
|
||||
platform: 'linux',
|
||||
arch: 'x64',
|
||||
};
|
||||
exports.TARGETS = {
|
||||
'aarch64-apple-darwin': aarch64AppleDarwin,
|
||||
'i686-pc-windows-msvc': i686PcWindowsMsvc,
|
||||
'x86_64-pc-windows-msvc': x8664PcWindowsMsvc,
|
||||
'x86_64-apple-darwin': x8664AppleDarwin,
|
||||
'x86_64-unknown-linux-gnu': x8664UnknownLinuxGnu,
|
||||
};
|
||||
// The set of targets we build by default, sorted by increasing complexity so
|
||||
// that we fail fast when the native host target fails.
|
||||
exports.ENABLED_TARGETS = [
|
||||
exports.TARGETS['x86_64-apple-darwin'],
|
||||
exports.TARGETS['aarch64-apple-darwin'],
|
||||
exports.TARGETS['x86_64-unknown-linux-gnu'],
|
||||
exports.TARGETS['i686-pc-windows-msvc'],
|
||||
];
|
||||
function getHost() {
|
||||
return Object.values(exports.TARGETS).find(target => (target.platform === process.platform &&
|
||||
target.arch === process.arch));
|
||||
}
|
||||
exports.getHost = getHost;
|
||||
function isHostId(id) {
|
||||
return getHost()?.id === id;
|
||||
}
|
||||
exports.isHostId = isHostId;
|
||||
function isHost(target) {
|
||||
return getHost()?.id === target.id;
|
||||
}
|
||||
exports.isHost = isHost;
|
||||
@@ -1,225 +0,0 @@
|
||||
/*
|
||||
Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
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 { GLIBC, MUSL, family as processLibC } from "detect-libc";
|
||||
|
||||
// We borrow Rust's target naming scheme as a way of expressing all target
|
||||
// details in a single string.
|
||||
// See https://doc.rust-lang.org/rustc/platform-support.html.
|
||||
export type TargetId =
|
||||
| "aarch64-apple-darwin"
|
||||
| "x86_64-apple-darwin"
|
||||
| "universal-apple-darwin"
|
||||
| "i686-pc-windows-msvc"
|
||||
| "x86_64-pc-windows-msvc"
|
||||
| "aarch64-pc-windows-msvc"
|
||||
| "i686-unknown-freebsd"
|
||||
| "x86_64-unknown-freebsd"
|
||||
| "aarch64-unknown-freebsd"
|
||||
| "i686-unknown-linux-musl"
|
||||
| "i686-unknown-linux-gnu"
|
||||
| "x86_64-unknown-linux-musl"
|
||||
| "x86_64-unknown-linux-gnu"
|
||||
| "aarch64-unknown-linux-musl"
|
||||
| "aarch64-unknown-linux-gnu"
|
||||
| "powerpc64le-unknown-linux-musl"
|
||||
| "powerpc64le-unknown-linux-gnu";
|
||||
|
||||
// Values are expected to match those used in `process.platform`.
|
||||
export type Platform = "darwin" | "freebsd" | "linux" | "win32";
|
||||
|
||||
// Values are expected to match those used in `process.arch`.
|
||||
export type Arch = "arm64" | "ia32" | "x64" | "ppc64" | "universal";
|
||||
|
||||
// Values are expected to match those used by Visual Studio's `vcvarsall.bat`.
|
||||
// See https://docs.microsoft.com/cpp/build/building-on-the-command-line?view=msvc-160#vcvarsall-syntax
|
||||
export type VcVarsArch = "amd64" | "arm64" | "x86";
|
||||
|
||||
export type Target = {
|
||||
id: TargetId;
|
||||
platform: Platform;
|
||||
arch: Arch;
|
||||
};
|
||||
|
||||
export type WindowsTarget = Target & {
|
||||
platform: "win32";
|
||||
vcVarsArch: VcVarsArch;
|
||||
};
|
||||
|
||||
export type LinuxTarget = Target & {
|
||||
platform: "linux";
|
||||
libC: typeof processLibC;
|
||||
};
|
||||
|
||||
export type UniversalTarget = Target & {
|
||||
arch: "universal";
|
||||
subtargets: Target[];
|
||||
};
|
||||
|
||||
const aarch64AppleDarwin: Target = {
|
||||
id: "aarch64-apple-darwin",
|
||||
platform: "darwin",
|
||||
arch: "arm64",
|
||||
};
|
||||
|
||||
const x8664AppleDarwin: Target = {
|
||||
id: "x86_64-apple-darwin",
|
||||
platform: "darwin",
|
||||
arch: "x64",
|
||||
};
|
||||
|
||||
const universalAppleDarwin: UniversalTarget = {
|
||||
id: "universal-apple-darwin",
|
||||
platform: "darwin",
|
||||
arch: "universal",
|
||||
subtargets: [aarch64AppleDarwin, x8664AppleDarwin],
|
||||
};
|
||||
|
||||
const i686PcWindowsMsvc: WindowsTarget = {
|
||||
id: "i686-pc-windows-msvc",
|
||||
platform: "win32",
|
||||
arch: "ia32",
|
||||
vcVarsArch: "x86",
|
||||
};
|
||||
|
||||
const x8664PcWindowsMsvc: WindowsTarget = {
|
||||
id: "x86_64-pc-windows-msvc",
|
||||
platform: "win32",
|
||||
arch: "x64",
|
||||
vcVarsArch: "amd64",
|
||||
};
|
||||
|
||||
const aarch64WindowsMsvc: WindowsTarget = {
|
||||
id: "aarch64-pc-windows-msvc",
|
||||
platform: "win32",
|
||||
arch: "arm64",
|
||||
vcVarsArch: "arm64",
|
||||
};
|
||||
|
||||
const i686UnknownFreebsd: Target = {
|
||||
id: "i686-unknown-freebsd",
|
||||
platform: "freebsd",
|
||||
arch: "ia32",
|
||||
};
|
||||
|
||||
const x8664UnknownFreebsd: Target = {
|
||||
id: "x86_64-unknown-freebsd",
|
||||
platform: "freebsd",
|
||||
arch: "x64",
|
||||
};
|
||||
|
||||
const aarch64UnknownFreebsd: Target = {
|
||||
id: "aarch64-unknown-freebsd",
|
||||
platform: "freebsd",
|
||||
arch: "arm64",
|
||||
};
|
||||
|
||||
const x8664UnknownLinuxGnu: LinuxTarget = {
|
||||
id: "x86_64-unknown-linux-gnu",
|
||||
platform: "linux",
|
||||
arch: "x64",
|
||||
libC: GLIBC,
|
||||
};
|
||||
|
||||
const x8664UnknownLinuxMusl: LinuxTarget = {
|
||||
id: "x86_64-unknown-linux-musl",
|
||||
platform: "linux",
|
||||
arch: "x64",
|
||||
libC: MUSL,
|
||||
};
|
||||
|
||||
const i686UnknownLinuxGnu: LinuxTarget = {
|
||||
id: "i686-unknown-linux-gnu",
|
||||
platform: "linux",
|
||||
arch: "ia32",
|
||||
libC: GLIBC,
|
||||
};
|
||||
|
||||
const i686UnknownLinuxMusl: LinuxTarget = {
|
||||
id: "i686-unknown-linux-musl",
|
||||
platform: "linux",
|
||||
arch: "ia32",
|
||||
libC: MUSL,
|
||||
};
|
||||
|
||||
const aarch64UnknownLinuxGnu: LinuxTarget = {
|
||||
id: "aarch64-unknown-linux-gnu",
|
||||
platform: "linux",
|
||||
arch: "arm64",
|
||||
libC: GLIBC,
|
||||
};
|
||||
|
||||
const aarch64UnknownLinuxMusl: LinuxTarget = {
|
||||
id: "aarch64-unknown-linux-musl",
|
||||
platform: "linux",
|
||||
arch: "arm64",
|
||||
libC: MUSL,
|
||||
};
|
||||
|
||||
const powerpc64leUnknownLinuxGnu: LinuxTarget = {
|
||||
id: "powerpc64le-unknown-linux-gnu",
|
||||
platform: "linux",
|
||||
arch: "ppc64",
|
||||
libC: GLIBC,
|
||||
};
|
||||
|
||||
const powerpc64leUnknownLinuxMusl: LinuxTarget = {
|
||||
id: "powerpc64le-unknown-linux-musl",
|
||||
platform: "linux",
|
||||
arch: "ppc64",
|
||||
libC: MUSL,
|
||||
};
|
||||
|
||||
export const TARGETS: Record<TargetId, Target> = {
|
||||
// macOS
|
||||
"aarch64-apple-darwin": aarch64AppleDarwin,
|
||||
"x86_64-apple-darwin": x8664AppleDarwin,
|
||||
"universal-apple-darwin": universalAppleDarwin,
|
||||
// Windows
|
||||
"i686-pc-windows-msvc": i686PcWindowsMsvc,
|
||||
"x86_64-pc-windows-msvc": x8664PcWindowsMsvc,
|
||||
"aarch64-pc-windows-msvc": aarch64WindowsMsvc,
|
||||
// FreeBSD
|
||||
"i686-unknown-freebsd": i686UnknownFreebsd,
|
||||
"x86_64-unknown-freebsd": x8664UnknownFreebsd,
|
||||
"aarch64-unknown-freebsd": aarch64UnknownFreebsd,
|
||||
// Linux
|
||||
"i686-unknown-linux-musl": i686UnknownLinuxMusl,
|
||||
"i686-unknown-linux-gnu": i686UnknownLinuxGnu,
|
||||
"x86_64-unknown-linux-musl": x8664UnknownLinuxMusl,
|
||||
"x86_64-unknown-linux-gnu": x8664UnknownLinuxGnu,
|
||||
"aarch64-unknown-linux-musl": aarch64UnknownLinuxMusl,
|
||||
"aarch64-unknown-linux-gnu": aarch64UnknownLinuxGnu,
|
||||
"powerpc64le-unknown-linux-musl": powerpc64leUnknownLinuxMusl,
|
||||
"powerpc64le-unknown-linux-gnu": powerpc64leUnknownLinuxGnu,
|
||||
};
|
||||
|
||||
export function getHost(): Target | undefined {
|
||||
return Object.values(TARGETS).find(
|
||||
(target) =>
|
||||
target.platform === process.platform &&
|
||||
target.arch === process.arch &&
|
||||
(process.platform !== "linux" || (target as LinuxTarget).libC === processLibC),
|
||||
);
|
||||
}
|
||||
|
||||
export function isHostId(id: TargetId): boolean {
|
||||
return getHost()?.id === id;
|
||||
}
|
||||
|
||||
export function isHost(target: Target): boolean {
|
||||
return getHost()?.id === target.id;
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
IMAGE=${DOCKER_IMAGE_NAME:-"element-desktop-dockerbuild"}
|
||||
|
||||
docker inspect "$IMAGE" 2> /dev/null > /dev/null
|
||||
docker inspect element-desktop-dockerbuild 2> /dev/null > /dev/null
|
||||
if [ $? != 0 ]; then
|
||||
echo "Docker image $IMAGE not found. Have you run yarn run docker:setup?"
|
||||
echo "Docker image element-desktop-dockerbuild not found. Have you run yarn run docker:setup?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -20,4 +18,4 @@ docker run --rm -ti \
|
||||
-v ${PWD}/docker/.gnupg:/root/.gnupg \
|
||||
-v ~/.cache/electron:/root/.cache/electron \
|
||||
-v ~/.cache/electron-builder:/root/.cache/electron-builder \
|
||||
"$IMAGE" "$@"
|
||||
element-desktop-dockerbuild "$@"
|
||||
|
||||
32
scripts/mkrepo.sh
Executable file
32
scripts/mkrepo.sh
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Take the deb and bundle it into a apt repository
|
||||
if [[ $# -lt 1 ]]
|
||||
then
|
||||
echo "Usage $0 <config dir>"
|
||||
exit
|
||||
fi
|
||||
|
||||
confdir=$1
|
||||
|
||||
set -ex
|
||||
|
||||
ver=`jq -r .version package.json`
|
||||
distdir=$PWD/dist
|
||||
confdir=$PWD/$confdir
|
||||
|
||||
repodir=`mktemp -d -t repo`
|
||||
mkdir $repodir/conf
|
||||
cp $confdir/conf_distributions $repodir/conf/distributions
|
||||
|
||||
pushd $repodir
|
||||
for i in `cat conf/distributions | grep Codename | cut -d ' ' -f 2`
|
||||
do
|
||||
reprepro includedeb $i $distdir/element-desktop_${ver}_amd64.deb
|
||||
done
|
||||
|
||||
tar cvzf $distdir/element-desktop_repo_$ver.tar.gz .
|
||||
|
||||
popd
|
||||
|
||||
rm -r $repodir
|
||||
55
scripts/set-version.js
Executable file
55
scripts/set-version.js
Executable file
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/*
|
||||
* Checks for the presence of a webapp, inspects its version and sets the
|
||||
* version metadata of the package to match.
|
||||
*/
|
||||
|
||||
const fs = require('fs').promises;
|
||||
const asar = require('asar');
|
||||
const childProcess = require('child_process');
|
||||
|
||||
async function versionFromAsar() {
|
||||
try {
|
||||
await fs.stat('webapp.asar');
|
||||
} catch (e) {
|
||||
console.log("No 'webapp.asar' found. Run 'yarn run fetch'");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return asar.extractFile('webapp.asar', 'version').toString().trim();
|
||||
}
|
||||
|
||||
async function setPackageVersion(ver) {
|
||||
// set version in package.json: electron-builder will use this to populate
|
||||
// all the various version fields
|
||||
await new Promise((resolve, reject) => {
|
||||
childProcess.execFile(process.platform === 'win32' ? 'yarn.cmd' : 'yarn', [
|
||||
'version',
|
||||
'-s',
|
||||
'--no-git-tag-version', // This also means "don't commit to git" as it turns out
|
||||
'--new-version',
|
||||
ver,
|
||||
], (err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function main(args) {
|
||||
let version = args[0];
|
||||
|
||||
if (version === undefined) version = await versionFromAsar();
|
||||
|
||||
await setPackageVersion(version);
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main(process.argv.slice(2)).then((ret) => process.exit(ret));
|
||||
}
|
||||
|
||||
module.exports = { versionFromAsar, setPackageVersion };
|
||||
@@ -1,64 +0,0 @@
|
||||
#!/usr/bin/env -S npx ts-node
|
||||
|
||||
/*
|
||||
* Checks for the presence of a webapp, inspects its version and sets the
|
||||
* version metadata of the package to match.
|
||||
*/
|
||||
|
||||
import { promises as fs } from "fs";
|
||||
import * as asar from "@electron/asar";
|
||||
import * as childProcess from "child_process";
|
||||
|
||||
export async function versionFromAsar(): Promise<string> {
|
||||
try {
|
||||
await fs.stat("webapp.asar");
|
||||
} catch (e) {
|
||||
throw new Error("No 'webapp.asar' found. Run 'yarn run fetch'");
|
||||
}
|
||||
|
||||
return asar.extractFile("webapp.asar", "version").toString().trim();
|
||||
}
|
||||
|
||||
export async function setPackageVersion(ver: string): Promise<void> {
|
||||
// set version in package.json: electron-builder will use this to populate
|
||||
// all the various version fields
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
childProcess.execFile(
|
||||
process.platform === "win32" ? "yarn.cmd" : "yarn",
|
||||
[
|
||||
"version",
|
||||
"-s",
|
||||
"--no-git-tag-version", // This also means "don't commit to git" as it turns out
|
||||
"--new-version",
|
||||
ver,
|
||||
],
|
||||
(err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
async function main(args: string[]): Promise<number> {
|
||||
let version = args[0];
|
||||
|
||||
if (version === undefined) version = await versionFromAsar();
|
||||
|
||||
await setPackageVersion(version);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main(process.argv.slice(2))
|
||||
.then((ret) => {
|
||||
process.exit(ret);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"resolveJsonModule": true,
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
"target": "es2017",
|
||||
"module": "commonjs",
|
||||
"sourceMap": false,
|
||||
"strict": true,
|
||||
"lib": ["es2020", "dom"]
|
||||
},
|
||||
"include": ["../src/@types", "./**/*.ts"],
|
||||
"ts-node": {
|
||||
"transpileOnly": true
|
||||
}
|
||||
}
|
||||
6
src/@types/glob.d.ts
vendored
6
src/@types/glob.d.ts
vendored
@@ -1,6 +0,0 @@
|
||||
import { GlobOptions } from "glob";
|
||||
|
||||
declare module "glob" {
|
||||
// Workaround for @electron/asar importing IOptions instead of GlobOptions
|
||||
export type IOptions = GlobOptions;
|
||||
}
|
||||
33
src/@types/global.d.ts
vendored
33
src/@types/global.d.ts
vendored
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2021 - 2022 New Vector Ltd
|
||||
Copyright 2021 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -15,31 +15,12 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
import { BrowserWindow } from "electron";
|
||||
import Store from "electron-store";
|
||||
import AutoLaunch from "auto-launch";
|
||||
|
||||
import { AppLocalization } from "../language-helper";
|
||||
|
||||
// global type extensions need to use var for whatever reason
|
||||
/* eslint-disable no-var */
|
||||
declare global {
|
||||
var mainWindow: BrowserWindow | null;
|
||||
var appQuitting: boolean;
|
||||
var appLocalization: AppLocalization;
|
||||
var launcher: AutoLaunch;
|
||||
var vectorConfig: Record<string, any>;
|
||||
var trayConfig: {
|
||||
// eslint-disable-next-line camelcase
|
||||
icon_path: string;
|
||||
brand: string;
|
||||
};
|
||||
var store: Store<{
|
||||
warnBeforeExit?: boolean;
|
||||
minimizeToTray?: boolean;
|
||||
spellCheckerEnabled?: boolean;
|
||||
autoHideMenuBar?: boolean;
|
||||
locale?: string | string[];
|
||||
disableHardwareAcceleration?: boolean;
|
||||
}>;
|
||||
namespace NodeJS {
|
||||
interface Global {
|
||||
mainWindow: BrowserWindow;
|
||||
appQuitting: boolean;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* eslint-enable no-var */
|
||||
|
||||
54
src/@types/keytar.d.ts
vendored
54
src/@types/keytar.d.ts
vendored
@@ -1,54 +0,0 @@
|
||||
// Based on https://github.com/atom/node-keytar/blob/master/keytar.d.ts because keytar is a hak-dependency and not a normal one
|
||||
// Definitions by: Milan Burda <https://github.com/miniak>, Brendan Forster <https://github.com/shiftkey>, Hari Juturu <https://github.com/juturu>
|
||||
// Adapted from DefinitelyTyped: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/keytar/index.d.ts
|
||||
|
||||
declare module "keytar" {
|
||||
/**
|
||||
* Get the stored password for the service and account.
|
||||
*
|
||||
* @param service The string service name.
|
||||
* @param account The string account name.
|
||||
*
|
||||
* @returns A promise for the password string.
|
||||
*/
|
||||
export function getPassword(service: string, account: string): Promise<string | null>;
|
||||
|
||||
/**
|
||||
* Add the password for the service and account to the keychain.
|
||||
*
|
||||
* @param service The string service name.
|
||||
* @param account The string account name.
|
||||
* @param password The string password.
|
||||
*
|
||||
* @returns A promise for the set password completion.
|
||||
*/
|
||||
export function setPassword(service: string, account: string, password: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* Delete the stored password for the service and account.
|
||||
*
|
||||
* @param service The string service name.
|
||||
* @param account The string account name.
|
||||
*
|
||||
* @returns A promise for the deletion status. True on success.
|
||||
*/
|
||||
export function deletePassword(service: string, account: string): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Find a password for the service in the keychain.
|
||||
*
|
||||
* @param service The string service name.
|
||||
*
|
||||
* @returns A promise for the password string.
|
||||
*/
|
||||
export function findPassword(service: string): Promise<string | null>;
|
||||
|
||||
/**
|
||||
* Find all accounts and passwords for `service` in the keychain.
|
||||
*
|
||||
* @param service The string service name.
|
||||
*
|
||||
* @returns A promise for the array of found credentials.
|
||||
*/
|
||||
export function findCredentials(service: string): Promise<Array<{ account: string; password: string }>>;
|
||||
}
|
||||
145
src/@types/matrix-seshat.d.ts
vendored
145
src/@types/matrix-seshat.d.ts
vendored
@@ -1,145 +0,0 @@
|
||||
/*
|
||||
Copyright 2022 New Vector 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 "matrix-seshat" {
|
||||
interface IConfig {
|
||||
language?: string;
|
||||
passphrase?: string;
|
||||
}
|
||||
|
||||
/* eslint-disable camelcase */
|
||||
interface IMatrixEvent {
|
||||
event_id: string;
|
||||
sender: string;
|
||||
room_id: string;
|
||||
origin_server_ts: number;
|
||||
content: Record<string, any>;
|
||||
}
|
||||
|
||||
interface IMatrixProfile {
|
||||
displayname?: string;
|
||||
avatar_url?: string;
|
||||
}
|
||||
|
||||
interface ISearchArgs {
|
||||
searchTerm: number;
|
||||
limit: number;
|
||||
before_limit: number;
|
||||
after_limit: number;
|
||||
order_by_recency: boolean;
|
||||
next_batch?: string;
|
||||
}
|
||||
|
||||
interface ISearchContext {
|
||||
events_before: IMatrixEvent[];
|
||||
events_after: IMatrixEvent[];
|
||||
profile_info: { [userId: string]: IMatrixProfile };
|
||||
}
|
||||
|
||||
interface ISearchResult {
|
||||
next_batch: string;
|
||||
count: number;
|
||||
results: Array<{
|
||||
rank: number;
|
||||
result: IMatrixEvent;
|
||||
context: ISearchContext;
|
||||
}>;
|
||||
}
|
||||
/* eslint-enable camelcase */
|
||||
|
||||
interface ICheckpoint {
|
||||
roomId: string;
|
||||
token: string;
|
||||
fullCrawl: boolean;
|
||||
direction: "b" | "f";
|
||||
}
|
||||
|
||||
interface IDatabaseStats {
|
||||
size: number;
|
||||
eventCount: number;
|
||||
roomCount: number;
|
||||
}
|
||||
|
||||
interface ILoadArgs {
|
||||
roomId: string;
|
||||
limit: number;
|
||||
fromEvent: string;
|
||||
direction: "b" | "f";
|
||||
}
|
||||
|
||||
interface ILoadResult {
|
||||
event: IMatrixEvent;
|
||||
matrixProfile: IMatrixProfile;
|
||||
}
|
||||
|
||||
export class Seshat {
|
||||
public constructor(path: string, config?: IConfig);
|
||||
public addEvent(matrixEvent: IMatrixEvent, profile?: IMatrixProfile): void;
|
||||
public deleteEvent(eventId: string): Promise<boolean>;
|
||||
public commit(force?: boolean): Promise<number>;
|
||||
public commitSync(wait?: boolean, force?: boolean): number;
|
||||
public reload(): void;
|
||||
public search(args: ISearchArgs): Promise<ISearchResult>;
|
||||
public searchSync(
|
||||
term: string,
|
||||
limit?: number,
|
||||
beforeLimit?: number,
|
||||
afterLimit?: number,
|
||||
orderByRecency?: boolean,
|
||||
): ISearchResult;
|
||||
public addHistoricEventsSync(
|
||||
events: IMatrixEvent[],
|
||||
newCheckpoint?: ICheckpoint,
|
||||
oldCheckpoint?: ICheckpoint,
|
||||
): boolean;
|
||||
public addHistoricEvents(
|
||||
events: IMatrixEvent[],
|
||||
newCheckpoint?: ICheckpoint,
|
||||
oldCheckpoint?: ICheckpoint,
|
||||
): Promise<boolean>;
|
||||
public addCrawlerCheckpoint(checkpoint: ICheckpoint): Promise<void>;
|
||||
public removeCrawlerCheckpoint(checkpoint: ICheckpoint): Promise<void>;
|
||||
public loadCheckpoints(): Promise<ICheckpoint[]>;
|
||||
public getSize(): Promise<number>;
|
||||
public getStats(): Promise<IDatabaseStats>;
|
||||
public delete(): Promise<void>;
|
||||
public shutdown(): Promise<void>;
|
||||
public changePassphrase(newPassphrase: string): Promise<void>;
|
||||
public isEmpty(): Promise<boolean>;
|
||||
public isRoomIndexed(roomId: string): Promise<boolean>;
|
||||
public getUserVersion(): Promise<number>;
|
||||
public setUserVersion(version: number): Promise<void>;
|
||||
public loadFileEvents(args: ILoadArgs): Promise<ILoadResult[]>;
|
||||
}
|
||||
|
||||
interface IRecoveryInfo {
|
||||
totalEvents: number;
|
||||
reindexedEvents: number;
|
||||
done: number;
|
||||
}
|
||||
|
||||
export class SeshatRecovery {
|
||||
public constructor(path: string, config?: IConfig);
|
||||
public info(): IRecoveryInfo;
|
||||
public getUserVersion(): Promise<number>;
|
||||
public shutdown(): Promise<void>;
|
||||
public reindex(): Promise<void>;
|
||||
}
|
||||
|
||||
export class ReindexError extends Error {
|
||||
public constructor(message?: string);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
Copyright 2023 New Vector 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 { Streams } from "electron";
|
||||
|
||||
type DisplayMediaCallback = (streams: Streams) => void;
|
||||
|
||||
let displayMediaCallback: DisplayMediaCallback | null;
|
||||
|
||||
export const getDisplayMediaCallback = (): DisplayMediaCallback | null => {
|
||||
return displayMediaCallback;
|
||||
};
|
||||
|
||||
export const setDisplayMediaCallback = (callback: DisplayMediaCallback | null): void => {
|
||||
displayMediaCallback = callback;
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user