feat: Support Windows for development

Signed-off-by: Artem Savchenko <armisav@gmail.com>
This commit is contained in:
Artem Savchenko
2026-02-02 13:43:31 +07:00
parent c86869f980
commit a8a72fe59b
58 changed files with 536 additions and 91 deletions
+23
View File
@@ -0,0 +1,23 @@
//
// Copyright © 2024 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public 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 https://www.eclipse.org/legal/epl-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 { spawnSync } = require('child_process')
const repoRoot = path.resolve(__dirname, '..', '..')
const args = ['docker:build', '-p', '20', '--to', '@hcengineering/pod-server', '--to', '@hcengineering/tool']
const result = spawnSync('rush', args, { stdio: 'inherit', cwd: repoRoot })
// Mimic "|| true" - always exit 0 so rush docker-server can continue to docker:up:server
process.exit(0)
+55
View File
@@ -0,0 +1,55 @@
//
// Copyright © 2024 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public 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 https://www.eclipse.org/legal/epl-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 { spawnSync } = require('child_process')
const repoRoot = path.resolve(__dirname, '..', '..')
const packages = [
'@hcengineering/pod-server',
'@hcengineering/pod-front',
'@hcengineering/prod',
'@hcengineering/pod-account',
'@hcengineering/pod-workspace',
'@hcengineering/pod-collaborator',
'@hcengineering/tool',
'@hcengineering/pod-print',
'@hcengineering/pod-sign',
'@hcengineering/pod-analytics-collector',
'@hcengineering/rekoni-service',
'@hcengineering/pod-ai-bot',
'@hcengineering/import-tool',
'@hcengineering/pod-stats',
'@hcengineering/pod-fulltext',
'@hcengineering/pod-love',
'@hcengineering/pod-mail',
'@hcengineering/pod-datalake',
'@hcengineering/pod-mail-worker',
'@hcengineering/pod-export',
'@hcengineering/pod-media',
'@hcengineering/pod-preview',
'@hcengineering/pod-link-preview',
'@hcengineering/pod-external',
'@hcengineering/pod-backup',
'@hcengineering/backup-api-pod',
'@hcengineering/pod-billing',
'@hcengineering/pod-process',
'@hcengineering/pod-rating',
'@hcengineering/pod-payment'
]
const args = ['docker:build', '-p', '20', ...packages.flatMap(p => ['--to', p])]
const result = spawnSync('rush', args, { stdio: 'inherit', cwd: repoRoot })
process.exit(result.status !== null ? result.status : 1)
+55
View File
@@ -0,0 +1,55 @@
//
// Copyright © 2024 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public 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 https://www.eclipse.org/legal/epl-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 fs = require('fs')
const path = require('path')
const { execSync, spawnSync } = require('child_process')
const image = process.argv[2]
if (!image) {
console.error('Usage: node docker_build.js <image-name> [.]')
process.exit(1)
}
const version = execSync('git rev-parse HEAD', { encoding: 'utf8' }).trim()
const cleanup = process.env.DOCKER_BUILD_CLEANUP === 'true'
const extra = (process.env.DOCKER_EXTRA || '').trim().split(/\s+/).filter(Boolean)
console.log('Building version:', version)
const dockerArgs = ['build', '-t', image, '-t', `${image}:${version}`, ...extra, '.']
const result = spawnSync('docker', dockerArgs, { stdio: 'inherit', cwd: process.cwd() })
if (result.status !== 0) {
process.exit(result.status)
}
if (cleanup) {
console.log('Cleaning up build artifacts...')
const dirs = ['bundle', 'dist', '.rush']
for (const dir of dirs) {
const fullPath = path.join(process.cwd(), dir)
if (fs.existsSync(fullPath)) {
console.log(' Removing', dir + '/')
fs.rmSync(fullPath, { recursive: true, force: true })
}
}
// Skip du -sh on Windows (no du); optional on Unix
try {
const size = execSync('du -sh . 2>/dev/null | cut -f1', { encoding: 'utf8' }).trim()
if (size) console.log(' Size after cleanup:', size)
} catch (_) {
// ignore
}
}
+48
View File
@@ -0,0 +1,48 @@
//
// Copyright © 2024 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public 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 https://www.eclipse.org/legal/epl-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 fs = require('fs')
const path = require('path')
const withIcons = process.argv.includes('--with-icons')
// Run from desktop-package or qms-desktop-package directory (cwd = package dir)
const distDir = path.join(process.cwd(), 'dist')
const desktopDist = path.join(process.cwd(), '..', 'desktop', 'dist')
const desktopEnv = path.join(process.cwd(), '..', 'desktop', '.env')
if (fs.existsSync(distDir)) {
fs.rmSync(distDir, { recursive: true, force: true })
}
fs.cpSync(desktopDist, distDir, { recursive: true })
if (fs.existsSync(desktopEnv)) {
fs.cpSync(desktopEnv, path.join(distDir, '.env'))
}
if (withIcons) {
const publicDir = path.join(distDir, 'ui', 'public')
fs.mkdirSync(publicDir, { recursive: true })
const srcDir = path.join(process.cwd(), 'src')
const iconPng = path.join(srcDir, 'AppIcon.png')
const iconIco = path.join(srcDir, 'AppIcon.ico')
if (fs.existsSync(iconPng)) {
fs.cpSync(iconPng, path.join(publicDir, 'AppIcon.png'))
}
if (fs.existsSync(iconIco)) {
fs.cpSync(iconIco, path.join(publicDir, 'AppIcon.ico'))
}
}
+42
View File
@@ -0,0 +1,42 @@
//
// Copyright © 2024 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public 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 https://www.eclipse.org/legal/epl-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 fs = require('fs')
const path = require('path')
const cwd = process.cwd()
const distDir = path.join(cwd, 'dist')
const prodDist = path.join(cwd, '..', '..', 'dev', 'prod', 'dist')
const prodPublic = path.join(cwd, '..', '..', 'dev', 'prod', 'public')
if (fs.existsSync(distDir)) {
fs.rmSync(distDir, { recursive: true, force: true })
}
fs.cpSync(prodDist, distDir, { recursive: true })
if (fs.existsSync(prodPublic)) {
const entries = fs.readdirSync(prodPublic, { withFileTypes: true })
for (const entry of entries) {
const src = path.join(prodPublic, entry.name)
const dest = path.join(distDir, entry.name)
fs.cpSync(src, dest, { recursive: true })
}
}
const configJson = path.join(distDir, 'config.json')
if (fs.existsSync(configJson)) {
fs.rmSync(configJson, { force: true })
}
+32
View File
@@ -0,0 +1,32 @@
//
// Copyright © 2026 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public 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 https://www.eclipse.org/legal/epl-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 { execSync, spawnSync } = require('child_process')
const scriptsDir = __dirname
const modelVersion = execSync('node show_version.js', { encoding: 'utf8', cwd: scriptsDir }).trim()
const version = execSync('node show_tag.js', { encoding: 'utf8', cwd: scriptsDir }).trim()
process.env.MODEL_VERSION = modelVersion
process.env.VERSION = version
const [cmd, ...args] = process.argv.slice(2)
if (!cmd) {
process.exit(1)
}
const command = [cmd, ...args].join(' ')
const result = spawnSync(command, { stdio: 'inherit', env: process.env, shell: true })
process.exit(result.status !== null ? result.status : 1)
+19 -13
View File
@@ -13,19 +13,25 @@
// limitations under the License.
//
const exec = require('child_process').exec
const execSync = require('child_process').execSync
exec('git describe --tags --abbrev=0', (err, stdout, stderr) => {
if (err !== null) {
console.log('"0.6.0"')
}
const rawVersion = stdout.trim().replace('v', '').replace('s', '').split('.')
if (rawVersion.length === 3) {
const version = {
major: parseInt(rawVersion[0]),
minor: parseInt(rawVersion[1]),
patch: parseInt(rawVersion[2])
function main() {
try {
const stdout = execSync('git describe --tags --abbrev=0', { encoding: 'utf8' })
const rawVersion = stdout.trim().replace('v', '').replace('s', '').split('.')
if (rawVersion.length === 3) {
const version = {
major: parseInt(rawVersion[0]),
minor: parseInt(rawVersion[1]),
patch: parseInt(rawVersion[2])
}
console.log(`"${version.major}.${version.minor}.${version.patch}"`)
return
}
console.log(`"${version.major}.${version.minor}.${version.patch}"`)
} catch (err) {
// git failed or no tags
}
})
console.log('"0.6.0"')
}
main()
+15 -17
View File
@@ -15,25 +15,23 @@
const fs = require('fs')
const path = require('path')
const exec = require('child_process').exec
const execSync = require('child_process').execSync
function main() {
exec('git describe --tags --abbrev=0', (err, stdout) => {
if (err !== null) {
console.log('"0.6.0"')
return
}
// Take version from file
let version
try {
const versionFilePath = path.resolve(__dirname, 'version.txt')
version = fs.readFileSync(versionFilePath, 'utf8').trim()
} catch (error) {
version = '"0.6.0"'
}
console.log(version)
})
try {
execSync('git describe --tags --abbrev=0', { encoding: 'utf8' })
} catch (err) {
console.log('"0.6.0"')
return
}
let version
try {
const versionFilePath = path.resolve(__dirname, 'version.txt')
version = fs.readFileSync(versionFilePath, 'utf8').trim()
} catch (error) {
version = '"0.6.0"'
}
console.log(version)
}
main()