diff --git a/.github/workflows/gh-release.yaml b/.github/workflows/gh-release.yaml index f5001395..142d36bd 100644 --- a/.github/workflows/gh-release.yaml +++ b/.github/workflows/gh-release.yaml @@ -18,8 +18,8 @@ jobs: arch: [x64,arm64] platform: [linux,macos,win] exclude: - - platform: win # need to debug it - + - platform: win + arch: arm64 steps: - name: Checkout diff --git a/Dockerfile.cli b/Dockerfile.cli index 90566d32..693260c4 100644 --- a/Dockerfile.cli +++ b/Dockerfile.cli @@ -19,13 +19,13 @@ ARG CLI_TARGET=macos-arm64 WORKDIR /app/packages/cli ENV PKG_CACHE_PATH=/pkg/cache RUN --mount=type=cache,id=livecycle/preevy-cli/pkg-cache,target=/pkg/cache \ - yarn pkg --compress GZip --no-dict --public --public-packages tslib --options max_old_space_size=4096 -t node18-${CLI_TARGET} . + yarn pkg --compress GZip --no-dict --public --public-packages tslib --options max_old_space_size=4096 -t node18-${CLI_TARGET} . --out-path /preevy/bin FROM scratch as cli ARG CLI_TARGET=macos-arm64 -COPY --link --from=pkg /app/packages/cli/preevy /preevy +COPY --link --from=pkg /preevy/bin/* / # use docker buildx build -f Dockerfile.cli --target=cli . --output=type=local,dest=./dist FROM docker:24-cli as release -COPY --from=pkg /app/packages/cli/preevy /usr/bin/ +COPY --from=pkg /preevy/bin/* /usr/bin/ CMD [ "preevy" ] diff --git a/build_utils/eslintrc.js b/build_utils/eslintrc.js index 51c38954..dacc41fe 100644 --- a/build_utils/eslintrc.js +++ b/build_utils/eslintrc.js @@ -34,7 +34,7 @@ module.exports = { plugins: ['import', 'jest', '@typescript-eslint'], rules: { 'no-void': ['warn', { allowAsStatement: true }], - 'linebreak-style': ['warn', isWindows ? 'windows' : 'unix'], + 'linebreak-style': ['warn', 'unix'], quotes: [ 'warn', 'single', diff --git a/packages/core/src/commands/up/index.ts b/packages/core/src/commands/up/index.ts index 27ccc386..b46f698e 100644 --- a/packages/core/src/commands/up/index.ts +++ b/packages/core/src/commands/up/index.ts @@ -140,12 +140,12 @@ const up = async ({ envId, debug, tunnelOpts, - sshPrivateKeyPath: path.join(remoteDir, sshPrivateKeyFile.remote), - knownServerPublicKeyPath: path.join(remoteDir, knownServerPublicKey.remote), + sshPrivateKeyPath: path.posix.join(remoteDir, sshPrivateKeyFile.remote), + knownServerPublicKeyPath: path.posix.join(remoteDir, knownServerPublicKey.remote), user: userAndGroup.join(':'), machineStatusCommand: await machineDriver.machineStatusCommand(machine), envMetadata: await envMetadata({ envId, version }), - composeModelPath: path.join(remoteDir, composeModelFilename), + composeModelPath: path.posix.join(remoteDir, composeModelFilename), privateMode: false, defaultAccess: 'public', composeProject: projectName, diff --git a/packages/core/src/compose/model.ts b/packages/core/src/compose/model.ts index 1f80edb2..57c0791e 100644 --- a/packages/core/src/compose/model.ts +++ b/packages/core/src/compose/model.ts @@ -69,6 +69,8 @@ const volumeSkipList = [ /^\/$/, ] +const toPosix = (x:string) => x.split(path.sep).join(path.posix.sep) + export const fixModelForRemote = async ( { skipServices = [], cwd, remoteBaseDir }: { skipServices?: string[] @@ -83,12 +85,11 @@ export const fixModelForRemote = async ( if (!path.isAbsolute(absolutePath)) { throw new Error(`expected absolute path: "${absolutePath}"`) } - - const relativePath = path.relative(cwd, absolutePath) + const relativePath = toPosix(path.relative(cwd, absolutePath)) return relativePath.startsWith('..') - ? path.join('absolute', absolutePath) - : path.join('relative', relativePath) + ? path.posix.join('absolute', absolutePath) + : path.posix.join('relative', relativePath) } const overrideSecretsOrConfigs = ( @@ -96,7 +97,7 @@ export const fixModelForRemote = async ( ) => mapValues(c ?? {}, secretOrConfig => { const remote = remotePath(secretOrConfig.file) filesToCopy.push({ local: secretOrConfig.file, remote }) - return { ...secretOrConfig, file: path.join(remoteBaseDir, remote) } + return { ...secretOrConfig, file: path.posix.join(remoteBaseDir, remote) } }) const overrideSecrets = overrideSecretsOrConfigs(model.secrets) @@ -137,7 +138,7 @@ export const fixModelForRemote = async ( filesToCopy.push({ local: volume.source, remote }) } - return { ...volume, source: path.join(remoteBaseDir, remote) } + return { ...volume, source: path.posix.join(remoteBaseDir, remote) } }, service.volumes)), }) }) diff --git a/packages/core/src/remote-files.ts b/packages/core/src/remote-files.ts index ba561625..2de1ad3c 100644 --- a/packages/core/src/remote-files.ts +++ b/packages/core/src/remote-files.ts @@ -2,4 +2,4 @@ import path from 'path' export const REMOTE_DIR_BASE = '/var/lib/preevy' -export const remoteProjectDir = (projectName: string) => path.join(REMOTE_DIR_BASE, 'projects', projectName) +export const remoteProjectDir = (projectName: string) => path.posix.join(REMOTE_DIR_BASE, 'projects', projectName) diff --git a/packages/core/src/ssh/client/files.ts b/packages/core/src/ssh/client/files.ts index b0c5536e..3fb0dfac 100644 --- a/packages/core/src/ssh/client/files.ts +++ b/packages/core/src/ssh/client/files.ts @@ -50,7 +50,7 @@ const expandDir = async (local: string | DirInfo | FileInfo) => { const di = await normalizeDirInfo(local) const entries = await Promise.all( // eslint-disable-next-line no-use-before-define - di.entries.map(e => expandFile(isDirEnt(e) ? path.join(di.path, e.name) : e)) + di.entries.map(e => expandFile(isDirEnt(e) ? path.posix.join(di.path, e.name) : e)) ) return { diff --git a/packages/core/src/ssh/client/sftp.ts b/packages/core/src/ssh/client/sftp.ts index cb59f5d9..38f06ec5 100644 --- a/packages/core/src/ssh/client/sftp.ts +++ b/packages/core/src/ssh/client/sftp.ts @@ -98,7 +98,7 @@ export const sftpClient = ( ...entries.map(f => self.putFile( { local: isDirEnt(f) ? path.join(p, f.name) : f, - remote: path.join(remote, pathFromStringOrFileInfo(f)), + remote: path.posix.join(remote, pathFromStringOrFileInfo(f)), }, options, )), diff --git a/packages/core/src/telemetry/machine-id.ts b/packages/core/src/telemetry/machine-id.ts index 6ce9ee13..bb9b5212 100644 --- a/packages/core/src/telemetry/machine-id.ts +++ b/packages/core/src/telemetry/machine-id.ts @@ -35,8 +35,9 @@ const calcMachineId = async () => { export const memoizedMachineId = async (dataDir: string) => { const dir = localFs(dataDir) - const filename = path.join(dataDir, 'machine-id') - const storedMachineId = await readFileOrUndefined(filename) + const filename = 'machine-id' + const filepath = path.join(dataDir, 'machine-id') + const storedMachineId = await readFileOrUndefined(filepath) if (storedMachineId) { return storedMachineId } diff --git a/packages/core/src/upload-files/tar.ts b/packages/core/src/upload-files/tar.ts index 6363fb76..9d9ff883 100644 --- a/packages/core/src/upload-files/tar.ts +++ b/packages/core/src/upload-files/tar.ts @@ -1,6 +1,7 @@ import util from 'util' import path from 'path' import fs from 'fs' +import { platform } from 'os' import { pack, Headers, Pack } from 'tar-stream' import { Writable, pipeline } from 'stream' import { EmitterConsumer } from '@preevy/common' @@ -8,11 +9,13 @@ import { TransferProgressEmitter, TransferProgressEvents, transferProgressEmitte import { FileInfo, FileToCopy } from './files' import { Visitor, fsWalker } from './walk' +const isWin = platform() === 'win32' + const headerFromStats = (local: FileInfo, remote: string): Headers | undefined => { const { stats, symlinkTarget } = local const header: Headers = { name: remote, - mode: stats.mode, + mode: isWin ? 0o777 : stats.mode, mtime: stats.mtime, size: stats.size, uid: stats.uid, @@ -121,7 +124,7 @@ export const tarStreamer = (initialFilesToCopy: FileToCopy[] = []) => { }, directoryEntry: (file: FileToCopy, entry: string) => ({ local: path.join(file.local, entry), - remote: path.join(file.remote, entry), + remote: path.posix.join(file.remote, entry), }), } diff --git a/packages/driver-gce/src/fs/index.ts b/packages/driver-gce/src/fs/index.ts index e69affa8..fd450df8 100644 --- a/packages/driver-gce/src/fs/index.ts +++ b/packages/driver-gce/src/fs/index.ts @@ -52,7 +52,7 @@ export const googleCloudStorageFs = async (url: string): Promise => { return { read: async (filename: string) => { try { - const [result] = await bucket.file(path.join(prefix, filename)).download() + const [result] = await bucket.file(path.posix.join(prefix, filename)).download() return result } catch (error) { if (!hasErrorCode(error, 404)) { @@ -63,7 +63,7 @@ export const googleCloudStorageFs = async (url: string): Promise => { }, write: async (filename: string, content: Buffer | string) => await stream.promises.pipeline( stream.Readable.from(content), - bucket.file(path.join(prefix, filename)).createWriteStream(), + bucket.file(path.posix.join(prefix, filename)).createWriteStream(), ), delete: async (filename: string) => { try { diff --git a/packages/driver-lightsail/src/fs/index.ts b/packages/driver-lightsail/src/fs/index.ts index ad8ba821..0f361dd5 100644 --- a/packages/driver-lightsail/src/fs/index.ts +++ b/packages/driver-lightsail/src/fs/index.ts @@ -53,7 +53,7 @@ export const s3fs = async (s3Url: string): Promise => { try { result = await s3.getObject({ Bucket: bucket, - Key: path.join(prefix, filename), + Key: path.posix.join(prefix, filename), }) } catch (err) { if (isNotFoundError(err)) { @@ -72,7 +72,7 @@ export const s3fs = async (s3Url: string): Promise => { async write(filename: string, content: Buffer | string) { await s3.putObject({ Bucket: bucket, - Key: path.join(prefix, filename), + Key: path.posix.join(prefix, filename), Body: content, }) }, @@ -80,7 +80,7 @@ export const s3fs = async (s3Url: string): Promise => { try { await s3.deleteObject({ Bucket: bucket, - Key: path.join(prefix, filename), + Key: path.posix.join(prefix, filename), }) } catch (err) { if (isNotFoundError(err)) {