From 331198625b35f18e70de9ff51e8e401ce6f3f0b4 Mon Sep 17 00:00:00 2001 From: JupiterPi Date: Thu, 2 Jan 2025 16:05:59 +0100 Subject: [PATCH 01/15] feat: install script for linux/macos --- install.sh | 43 +++++++++++++++++++++++++++++++++++++++++++ src/util/util.ts | 38 +++++++++++++++++++++----------------- 2 files changed, 64 insertions(+), 17 deletions(-) create mode 100644 install.sh diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..41d02ca --- /dev/null +++ b/install.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +# determine platform as "linux" or "macos" +if [[ "$(uname -s)" == "Linux" ]] ; then + platform=linux +elif [[ "$(uname -s)" == "Darwin" ]] ; then + platform=macos +fi + +# determine architecture as "x64" or "arm64" +if [[ "$(uname -m)" == "aarch64" || "$(uname -m)" == "arm64" ]] ; then + arch=arm64 +else + arch=x64 +fi + +# fetch release info +latest_release=$(curl -s https://api.github.com/repos/FilenCloudDienste/filen-cli/releases/latest) +version=$(echo "$latest_release" | grep "tag_name" | cut -d \" -f 4) +download_url=$(echo "$latest_release" | grep "browser_download_url.*$platform-$arch" | cut -d \" -f 4) + +echo "Installing Filen CLI $version ($platform-$arch)" + +# prepare install location ~/.filen-cli +location=~/.filen-cli +if [ ! -d $location ] ; then mkdir -p $location/bin ; fi + +# download binary and make executable +echo "Downloading $download_url..." +curl -o $location/bin/filen -L --progress-bar $download_url +chmod +x $location/bin/filen + +# add to PATH +if [[ $PATH == *"$location"* ]] ; then + echo "\$PATH already contains $location" +else + export PATH=$PATH:$location/bin + printf "\n\n# filen-cli\nPATH=\$PATH:$location/bin\n" >> ~/.profile + echo "Added $location/bin to \$PATH in ~/.profile" +fi +echo "Filen CLI installed as \`filen\` (you might need to restart your shell)" + +echo "To uninstall, delete $location and revert changes to ~/.profile" diff --git a/src/util/util.ts b/src/util/util.ts index d2f52d1..d35066b 100644 --- a/src/util/util.ts +++ b/src/util/util.ts @@ -59,33 +59,37 @@ export async function directorySize(path: PathLike) { * Returns the platform-specific directory for storing configuration files. * Creates the directory if it doesn't exist. * - Windows: `%APPDATA%\filen-cli` - * - OS X: `~/Library/Application Support/filen-cli` - * - Unix: `$XDG_CONFIG_HOME/filen-cli` or `~/.config/filen-cli` + * - OS X: `~/Library/Application Support/filen-cli` (or `~/.filen-cli`) + * - Unix: `$XDG_CONFIG_HOME/filen-cli` or `~/.config/filen-cli` (or `~/.filen-cli`) */ export function platformConfigPath(): string { - // see https://github.com/jprichardson/ospath/blob/master/index.js - - let configPath - - switch (process.platform) { - case "win32": - configPath = pathModule.resolve(process.env.APPDATA!) - break - case "darwin": - configPath = pathModule.resolve(pathModule.join(os.homedir(), "Library/Application Support/")) - break - default: - configPath = process.env.XDG_CONFIG_HOME + // default config path, see https://github.com/jprichardson/ospath/blob/master/index.js + let configPath: string = (() => { + switch (process.platform) { + case "win32": return pathModule.resolve(process.env.APPDATA!) + case "darwin": return pathModule.resolve(pathModule.join(os.homedir(), "Library/Application Support/")) + default: return process.env.XDG_CONFIG_HOME ? pathModule.resolve(process.env.XDG_CONFIG_HOME) : pathModule.resolve(pathModule.join(os.homedir(), ".config/")) - break + } + })() + + // use install location of install.sh, if it exists + if (fsModule.existsSync(pathModule.join(os.homedir(), ".filen-cli"))) { + configPath = pathModule.resolve(pathModule.join(os.homedir(), ".filen-cli")) } if (!configPath || configPath.length === 0) { throw new Error("Could not find homedir path.") } - configPath = !isDevelopment ? pathModule.join(configPath, "filen-cli") : pathModule.join(configPath, "filen-cli", "dev") + if (!(configPath.includes("filen-cli"))) { + configPath = pathModule.join(configPath, "filen-cli") + } + + if (isDevelopment) { + configPath = pathModule.join(configPath, "dev") + } if (!fsModule.existsSync(configPath)) { fsModule.mkdirSync(configPath, { From f2e99202052b3f5e088e3e294bc6622ec652f00f Mon Sep 17 00:00:00 2001 From: JupiterPi Date: Thu, 2 Jan 2025 16:17:58 +0100 Subject: [PATCH 02/15] fix: check if already installed --- install.sh | 86 +++++++++++++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 39 deletions(-) diff --git a/install.sh b/install.sh index 41d02ca..36c2e91 100644 --- a/install.sh +++ b/install.sh @@ -1,43 +1,51 @@ #!/usr/bin/env bash -# determine platform as "linux" or "macos" -if [[ "$(uname -s)" == "Linux" ]] ; then - platform=linux -elif [[ "$(uname -s)" == "Darwin" ]] ; then - platform=macos -fi - -# determine architecture as "x64" or "arm64" -if [[ "$(uname -m)" == "aarch64" || "$(uname -m)" == "arm64" ]] ; then - arch=arm64 +# check if filen-cli is already installed +if [[ ! -z $(which filen) ]] ; then + echo "Filen CLI is already installed" + echo "You can install a different version using \`filen install \` or \`filen install latest\`" + echo "To uninstall, delete ~/.filen-cli and revert changes to ~/.profile" else - arch=x64 -fi -# fetch release info -latest_release=$(curl -s https://api.github.com/repos/FilenCloudDienste/filen-cli/releases/latest) -version=$(echo "$latest_release" | grep "tag_name" | cut -d \" -f 4) -download_url=$(echo "$latest_release" | grep "browser_download_url.*$platform-$arch" | cut -d \" -f 4) - -echo "Installing Filen CLI $version ($platform-$arch)" - -# prepare install location ~/.filen-cli -location=~/.filen-cli -if [ ! -d $location ] ; then mkdir -p $location/bin ; fi - -# download binary and make executable -echo "Downloading $download_url..." -curl -o $location/bin/filen -L --progress-bar $download_url -chmod +x $location/bin/filen - -# add to PATH -if [[ $PATH == *"$location"* ]] ; then - echo "\$PATH already contains $location" -else - export PATH=$PATH:$location/bin - printf "\n\n# filen-cli\nPATH=\$PATH:$location/bin\n" >> ~/.profile - echo "Added $location/bin to \$PATH in ~/.profile" -fi -echo "Filen CLI installed as \`filen\` (you might need to restart your shell)" - -echo "To uninstall, delete $location and revert changes to ~/.profile" + # determine platform as "linux" or "macos" + if [[ "$(uname -s)" == "Linux" ]] ; then + platform=linux + elif [[ "$(uname -s)" == "Darwin" ]] ; then + platform=macos + fi + + # determine architecture as "x64" or "arm64" + if [[ "$(uname -m)" == "aarch64" || "$(uname -m)" == "arm64" ]] ; then + arch=arm64 + else + arch=x64 + fi + + # fetch release info + latest_release=$(curl -s https://api.github.com/repos/FilenCloudDienste/filen-cli/releases/latest) + version=$(echo "$latest_release" | grep "tag_name" | cut -d \" -f 4) + download_url=$(echo "$latest_release" | grep "browser_download_url.*$platform-$arch" | cut -d \" -f 4) + + echo "Installing Filen CLI $version ($platform-$arch)" + + # prepare install location ~/.filen-cli + if [ ! -d ~/.filen-cli ] ; then mkdir -p ~/.filen-cli/bin ; fi + + # download binary and make executable + echo "Downloading $download_url..." + curl -o ~/.filen-cli/bin/filen -L --progress-bar $download_url + chmod +x ~/.filen-cli/bin/filen + + # add to PATH + if [[ $PATH == *"~/.filen-cli"* ]] ; then + echo "\$PATH already contains ~/.filen-cli" + else + export PATH=$PATH:~/.filen-cli/bin + printf "\n\n# filen-cli\nPATH=\$PATH:~/.filen-cli/bin\n" >> ~/.profile + echo "Added ~/.filen-cli/bin to \$PATH in ~/.profile" + fi + echo "Filen CLI installed as \`filen\` (you might need to restart your shell)" + + echo "To uninstall, delete ~/.filen-cli and revert changes to ~/.profile" + +fi \ No newline at end of file From c38e0db0b8ca6c93aaa5f921426025315af91514 Mon Sep 17 00:00:00 2001 From: JupiterPi Date: Thu, 2 Jan 2025 16:25:31 +0100 Subject: [PATCH 03/15] fix: cache platformConfigPath() --- src/util/util.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/util/util.ts b/src/util/util.ts index d35066b..ab1ff31 100644 --- a/src/util/util.ts +++ b/src/util/util.ts @@ -55,6 +55,7 @@ export async function directorySize(path: PathLike) { return (await Promise.all(stats)).reduce((accumulator, { size }) => accumulator + size, 0) } +let _platformConfigPath: string | undefined = undefined /** * Returns the platform-specific directory for storing configuration files. * Creates the directory if it doesn't exist. @@ -63,6 +64,8 @@ export async function directorySize(path: PathLike) { * - Unix: `$XDG_CONFIG_HOME/filen-cli` or `~/.config/filen-cli` (or `~/.filen-cli`) */ export function platformConfigPath(): string { + if (_platformConfigPath !== undefined) return _platformConfigPath + // default config path, see https://github.com/jprichardson/ospath/blob/master/index.js let configPath: string = (() => { switch (process.platform) { @@ -97,6 +100,7 @@ export function platformConfigPath(): string { }) } + _platformConfigPath = configPath return configPath } From 2ba9614c1654f2fe8e14046c54194dec027e8628 Mon Sep 17 00:00:00 2001 From: JupiterPi Date: Fri, 10 Jan 2025 20:00:04 +0100 Subject: [PATCH 04/15] fix: more shell profile files --- install.sh | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/install.sh b/install.sh index 36c2e91..abe2f3e 100644 --- a/install.sh +++ b/install.sh @@ -2,23 +2,23 @@ # check if filen-cli is already installed if [[ ! -z $(which filen) ]] ; then - echo "Filen CLI is already installed" - echo "You can install a different version using \`filen install \` or \`filen install latest\`" - echo "To uninstall, delete ~/.filen-cli and revert changes to ~/.profile" + echo "Filen CLI is already installed" + echo "You can install a different version using \`filen install \` or \`filen install latest\`" + echo "To uninstall, delete ~/.filen-cli and revert changes to your shell profile(s)" else # determine platform as "linux" or "macos" if [[ "$(uname -s)" == "Linux" ]] ; then - platform=linux + platform=linux elif [[ "$(uname -s)" == "Darwin" ]] ; then - platform=macos + platform=macos fi # determine architecture as "x64" or "arm64" if [[ "$(uname -m)" == "aarch64" || "$(uname -m)" == "arm64" ]] ; then - arch=arm64 + arch=arm64 else - arch=x64 + arch=x64 fi # fetch release info @@ -37,15 +37,24 @@ else chmod +x ~/.filen-cli/bin/filen # add to PATH - if [[ $PATH == *"~/.filen-cli"* ]] ; then - echo "\$PATH already contains ~/.filen-cli" + if [[ $PATH == *$(echo ~)/\.filen-cli* ]] ; then + echo "\$PATH already contains ~/.filen-cli" else - export PATH=$PATH:~/.filen-cli/bin - printf "\n\n# filen-cli\nPATH=\$PATH:~/.filen-cli/bin\n" >> ~/.profile - echo "Added ~/.filen-cli/bin to \$PATH in ~/.profile" + export PATH=$PATH:~/.filen-cli/bin + profileFileFound=0 + for profileFile in ~/.bashrc ~/.bash_profile ~/.zshrc ~/.profile ; do + if [[ -f $profileFile ]] ; then + profileFileFound=1 + printf "\n\n# filen-cli\nPATH=\$PATH:~/.filen-cli/bin\n" >> $profileFile + echo "Added ~/.filen-cli/bin to \$PATH in $profileFile" + fi + done + if [[ $profileFileFound == "0" ]] ; then + echo "ERR: No shell profile file found (checked: ~/.bashrc ~/.bash_profile ~/.zshrc ~/.profile)" + fi fi echo "Filen CLI installed as \`filen\` (you might need to restart your shell)" - echo "To uninstall, delete ~/.filen-cli and revert changes to ~/.profile" + echo "To uninstall, delete ~/.filen-cli and revert changes to your shell profile(s)" fi \ No newline at end of file From f801c3eaf0b482d1a17c58e704fcef36e28096f6 Mon Sep 17 00:00:00 2001 From: JupiterPi Date: Sun, 19 Jan 2025 17:45:00 +0100 Subject: [PATCH 05/15] feat: distribute as NPM package --- .github/workflows/build-and-publish.yml | 20 ++++++++++ .vscode/settings.json | 2 +- README.md | 2 + package-lock.json | 52 +++++++++++++------------ package.json | 12 ++++-- src/index.ts | 2 + src/updater.ts | 8 ++++ 7 files changed, 69 insertions(+), 29 deletions(-) diff --git a/.github/workflows/build-and-publish.yml b/.github/workflows/build-and-publish.yml index 4588bcd..2232104 100644 --- a/.github/workflows/build-and-publish.yml +++ b/.github/workflows/build-and-publish.yml @@ -57,6 +57,26 @@ jobs: dist/filen-cli-${{ github.event.release.tag_name }}-linux-arm64 dist/filen-cli-${{ github.event.release.tag_name }}-macos-arm64 + build-and-publish-npm: + name: Build and publish to npm + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Set version + uses: jacobtomlinson/gha-find-replace@v3 + with: + include: "package.json" + find: '"version": "0.0.0"' + replace: '"version": "${{ github.event.release.tag_name }}"' + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: "20.x" + - run: npm ci + - run: npm run build + - run: npm publish + build-and-publish-docker: name: Build docker image runs-on: ubuntu-latest diff --git a/.vscode/settings.json b/.vscode/settings.json index 3412dd9..ec85e91 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,7 @@ { "files.eol": "\n", "editor.formatOnPaste": false, - "editor.formatOnSave": true, + "editor.formatOnSave": false, "editor.formatOnType": false, "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.codeActionsOnSave": { diff --git a/README.md b/README.md index 4b45050..caec399 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,8 @@ Use the `--auto-update` flag to skip the confirmation prompt and update automati You can always install any version using `filen install `, `filen install latest` or `filen install canary`. +The CLI is also available as an NPM package, which can be installed with `npm install --global @filen/cli` and then invoked as `filen`. The NPM repository always contains the latest canary releases (see below). + ### Canary releases If you want to be among the first to try out new features and fixes, you can enable canary releases, diff --git a/package-lock.json b/package-lock.json index 3182ed5..66899bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,18 @@ { - "name": "filen-cli", + "name": "@filen/cli", "version": "0.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "filen-cli", + "name": "@filen/cli", "version": "0.0.0", "license": "AGPLv3", "dependencies": { "@filen/network-drive": "^0.9.40", - "@filen/s3": "^0.2.50", - "@filen/sdk": "^0.1.191", - "@filen/sync": "^0.1.95", + "@filen/s3": "^0.2.51", + "@filen/sdk": "^0.1.192", + "@filen/sync": "^0.1.96", "@filen/webdav": "^0.2.64", "@types/mute-stream": "^0.0.4", "arg": "^5.0.2", @@ -24,6 +24,9 @@ "semver": "^7.6.3", "uuid-by-string": "^4.0.0" }, + "bin": { + "filen": "build/index.js" + }, "devDependencies": { "@types/cli-progress": "^3.11.6", "@types/jest": "^29.5.12", @@ -1313,6 +1316,15 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@filen/aws4-express": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@filen/aws4-express/-/aws4-express-0.10.2.tgz", + "integrity": "sha512-k8WExS1UZ9uV3uEWinf2cwFeB3AzDy0KnDcrX72Liajl/cU6GIZzLFXOIubsZIBVvz/AXPiX1iEwYAHsvTdlYw==", + "license": "SEE LICENSE IN LICENSE", + "dependencies": { + "express": "^4.21.1" + } + }, "node_modules/@filen/network-drive": { "version": "0.9.40", "resolved": "https://registry.npmjs.org/@filen/network-drive/-/network-drive-0.9.40.tgz", @@ -1371,14 +1383,14 @@ } }, "node_modules/@filen/s3": { - "version": "0.2.50", - "resolved": "https://registry.npmjs.org/@filen/s3/-/s3-0.2.50.tgz", - "integrity": "sha512-Gaih6O/gpSLNPRTkYmzdcoUAf/VpDuAdPgbjor9kkb9O2Gg56NY15Qr0ppGp1CmzyQInUeQKHriitIg7Vuzrjg==", + "version": "0.2.51", + "resolved": "https://registry.npmjs.org/@filen/s3/-/s3-0.2.51.tgz", + "integrity": "sha512-rQDPwi0EdMx4CtSZ8mvYDgLFOtIIyPzP0X/gLoK1obG0/pclPkCmipjiDVM4fdEFCojPk8b2QlBSjJQbovM+og==", "license": "AGPLv3", "dependencies": { - "@filen/sdk": "^0.1.191", + "@filen/aws4-express": "^0.10.2", + "@filen/sdk": "^0.1.192", "aws-sdk": "^2.1692.0", - "aws4-express": "github:FilenCloudDienste/aws4-express", "body-parser": "^1.20.2", "dayjs": "^1.11.11", "express": "^4.19.2", @@ -1423,9 +1435,9 @@ } }, "node_modules/@filen/sdk": { - "version": "0.1.191", - "resolved": "https://registry.npmjs.org/@filen/sdk/-/sdk-0.1.191.tgz", - "integrity": "sha512-JwlDuUKaGMKgX54AHkSVCHKbEappi4S/3qX1CcWY76ZZt/+RDr3AdzMKIvt7hgM9YFAEzByBsnHk/6GloIR6rA==", + "version": "0.1.192", + "resolved": "https://registry.npmjs.org/@filen/sdk/-/sdk-0.1.192.tgz", + "integrity": "sha512-f5YmNdPoKNJ08zHt4k6enuNvDZ95RaTlFQVbhNpKL4GQNza1kbpks7AYJBieGqp7DiWg9HskF2YZ2rKz7oISbQ==", "license": "AGPLv3", "dependencies": { "agentkeepalive": "^4.5.0", @@ -1497,9 +1509,9 @@ } }, "node_modules/@filen/sync": { - "version": "0.1.95", - "resolved": "https://registry.npmjs.org/@filen/sync/-/sync-0.1.95.tgz", - "integrity": "sha512-Dsy8blLmmPTE3WrEELWGI2Zrid61cIEbSqVnNNcqb/eyng4onoYhl/xZKtyIA1UmYqhGVS+F25luMHFjMptQaQ==", + "version": "0.1.96", + "resolved": "https://registry.npmjs.org/@filen/sync/-/sync-0.1.96.tgz", + "integrity": "sha512-F5sDXJecSFvK9lecFS9U8n0HdzGzW3CN0XyGY9D1WzJsVSAaMfGXxRQMXAClZ4ey4bvMXgG336Bct2HExOlHSw==", "license": "AGPLv3", "dependencies": { "@filen/sdk": "^0.1.191", @@ -3405,14 +3417,6 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/aws4-express": { - "version": "0.10.2", - "resolved": "git+ssh://git@github.com/FilenCloudDienste/aws4-express.git#b5dcf34d9cbe3fb48aa4641f35ad74ab7cb67f91", - "license": "SEE LICENSE IN LICENSE", - "dependencies": { - "express": "^4.21.1" - } - }, "node_modules/axios": { "version": "1.7.7", "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", diff --git a/package.json b/package.json index 9be2a75..73abe8e 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "filen-cli", + "name": "@filen/cli", "version": "0.0.0", "description": "Filen CLI", "main": "build/index.js", @@ -14,6 +14,10 @@ "package-all": "npm run build && node packageAllPlatforms.mjs", "bump-filen-dependencies": "npm i @filen/sdk@latest @filen/sync@latest @filen/webdav@latest @filen/s3@latest @filen/network-drive@latest" }, + "bin": { + "filen": "build/index.js" + }, + "files": [ "build" ], "engines": { "node": "20" }, @@ -28,9 +32,9 @@ "license": "AGPLv3", "dependencies": { "@filen/network-drive": "^0.9.40", - "@filen/s3": "^0.2.50", - "@filen/sdk": "^0.1.191", - "@filen/sync": "^0.1.95", + "@filen/s3": "^0.2.51", + "@filen/sdk": "^0.1.192", + "@filen/sync": "^0.1.96", "@filen/webdav": "^0.2.64", "@types/mute-stream": "^0.0.4", "arg": "^5.0.2", diff --git a/src/index.ts b/src/index.ts index 3e45500..53b646d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,5 @@ +#!/usr/bin/env node + import arg from "arg" import FilenSDK from "@filen/sdk" import path from "path" diff --git a/src/updater.ts b/src/updater.ts index 63b2338..b41d3d1 100644 --- a/src/updater.ts +++ b/src/updater.ts @@ -36,6 +36,13 @@ export class Updater { * @param autoUpdate the `--auto-update` CLI argument */ public async checkForUpdates(forceUpdateCheck: boolean, autoUpdate: boolean): Promise { + if ((process.pkg === undefined ? __filename : process.argv[0]!).endsWith(".js")) { + outVerbose("Skipping updates for non-binary installation") + return + } + + // todo: different update checking when executed as NPM package + if (version === "0.0.0") { outVerbose("Skipping updates in development environment") return @@ -260,6 +267,7 @@ export class Updater { private async installVersion(currentVersionName: string, publishedVersionName: string, downloadUrl: string) { const selfApplicationFile = process.pkg === undefined ? __filename : process.argv[0]! + if (selfApplicationFile.endsWith(".js")) errExit("Updater only supported for CLI binaries") const downloadedFile = path.join(path.dirname(selfApplicationFile), `filen_update_${publishedVersionName}`) out("Downloading update...") From ef71903465d217b18b3209f7603cb8e29195d69e Mon Sep 17 00:00:00 2001 From: JupiterPi Date: Sun, 19 Jan 2025 18:38:57 +0100 Subject: [PATCH 06/15] feat: check NPM registry for updates when running as NPM package --- .github/workflows/build-and-publish.yml | 6 ++++-- injectBuildInfo.mjs | 2 ++ package.json | 3 ++- src/buildInfo.ts | 4 ++++ src/updater.ts | 26 ++++++++++++++++++++++--- 5 files changed, 35 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-and-publish.yml b/.github/workflows/build-and-publish.yml index 2232104..8d03399 100644 --- a/.github/workflows/build-and-publish.yml +++ b/.github/workflows/build-and-publish.yml @@ -60,6 +60,7 @@ jobs: build-and-publish-npm: name: Build and publish to npm runs-on: ubuntu-latest + #todo: if: ${{ github.event.release.prerelease == false }} steps: - name: Checkout uses: actions/checkout@v3 @@ -74,8 +75,9 @@ jobs: with: node-version: "20.x" - run: npm ci - - run: npm run build - - run: npm publish + - run: npm publish # includes build + env: + FILEN_IS_NPM_PACKAGE: true build-and-publish-docker: name: Build docker image diff --git a/injectBuildInfo.mjs b/injectBuildInfo.mjs index 8cfed30..c6dd346 100644 --- a/injectBuildInfo.mjs +++ b/injectBuildInfo.mjs @@ -4,6 +4,7 @@ import * as fs from "fs" const version = JSON.parse(fs.readFileSync("package.json").toString()).version const isContainer = process.env.FILEN_IS_CONTAINER === "true" +const isNPMPackage = process.env.FILEN_IS_NPM_PACKAGE === "true" const key = process.env.FILEN_CLI_CRYPTO_BASE_KEY ?? fs.readFileSync("key").toString().split("\n")[0] const injectionFile = "build/buildInfo.js" @@ -11,6 +12,7 @@ let content = fs.readFileSync(injectionFile).toString() const buildInfo = { VERSION: `"${version}"`, IS_CONTAINER: `${isContainer}`, + IS_NPM_PACKAGE: `${isNPMPackage}`, CRYPTO_BASE_KEY: `"${key}"`, } Object.entries(buildInfo).forEach(entry => { diff --git a/package.json b/package.json index 73abe8e..9853217 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "package-dev": "npm run build && pkg -t node20 -o dist/filen-cli dist/bundle.js", "package-dev-all": "npm run build && node packageAllPlatforms.mjs dev", "package-all": "npm run build && node packageAllPlatforms.mjs", - "bump-filen-dependencies": "npm i @filen/sdk@latest @filen/sync@latest @filen/webdav@latest @filen/s3@latest @filen/network-drive@latest" + "bump-filen-dependencies": "npm i @filen/sdk@latest @filen/sync@latest @filen/webdav@latest @filen/s3@latest @filen/network-drive@latest", + "prepublishOnly": "node -e \"if (process.env.FILEN_IS_NPM_PACKAGE !== 'true') process.exit(1)\" && npm run build" }, "bin": { "filen": "build/index.js" diff --git a/src/buildInfo.ts b/src/buildInfo.ts index 66c508d..e3d5e25 100644 --- a/src/buildInfo.ts +++ b/src/buildInfo.ts @@ -6,10 +6,14 @@ export const version: string = "{{INJECT: VERSION}}" // @ts-expect-error will be injected export const disableUpdates: boolean = "{{INJECT: IS_CONTAINER}}" +// @ts-expect-error will be injected +export const isRunningAsNPMPackage: boolean = "{{INJECT: IS_NPM_PACKAGE}}" + export const key: string = "{{INJECT: CRYPTO_BASE_KEY}}" export function checkInjectedBuildInfo() { return version !== "{{INJECT: VERSION}}" && (disableUpdates.toString() === "true" || disableUpdates.toString() === "false") + && (isRunningAsNPMPackage.toString() === "true" || isRunningAsNPMPackage.toString() === "false") && key !== "{{INJECT: CRYPTO_BASE_KEY}}" } \ No newline at end of file diff --git a/src/updater.ts b/src/updater.ts index b41d3d1..757e7f2 100644 --- a/src/updater.ts +++ b/src/updater.ts @@ -1,4 +1,4 @@ -import { disableUpdates, version } from "./buildInfo" +import { disableUpdates, isRunningAsNPMPackage, version } from "./buildInfo" import { err, errExit, out, outVerbose, promptYesNo } from "./interface/interface" import path from "path" import { spawn } from "node:child_process" @@ -41,13 +41,17 @@ export class Updater { return } - // todo: different update checking when executed as NPM package - if (version === "0.0.0") { outVerbose("Skipping updates in development environment") return } + // check NPM registry instead if running as NPM package + if (isRunningAsNPMPackage) { + await this.checkNPMRegistryForUpdates() + return + } + const updateCache = await this.readUpdateCache() // skip if already recently checked @@ -126,6 +130,22 @@ export class Updater { await this.writeUpdateCache({ ...updateCache, lastCheckedUpdate: Date.now() }) } + private async checkNPMRegistryForUpdates() { + try { + const response = await fetch("https://registry.npmjs.org/filen-cli") + if (response.status !== 200) throw new Error(`NPM registry API returned status ${response.status} ${response.statusText}`) + const data = await response.json() + + const latestVersion = data["dist-tags"]["latest"] + if (latestVersion === undefined) throw new Error("latest version not found in NPM registry response") + if (latestVersion !== version) { + out(`Update available: ${version} -> ${latestVersion} (install via npm i -g @filen/cli@latest)`) + } + } catch (e) { + errExit("check NPM registry for updates", e) + } + } + /** * Shows a prompt to the user to enable or disable canary releases. */ From c93688ebebb51e30f5353fab6ef274df98b12efd Mon Sep 17 00:00:00 2001 From: JupiterPi Date: Sun, 19 Jan 2025 18:40:19 +0100 Subject: [PATCH 07/15] fix: don't publish Docker image of pre-release --- .github/workflows/build-and-publish.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-and-publish.yml b/.github/workflows/build-and-publish.yml index 8d03399..ef4061a 100644 --- a/.github/workflows/build-and-publish.yml +++ b/.github/workflows/build-and-publish.yml @@ -82,6 +82,7 @@ jobs: build-and-publish-docker: name: Build docker image runs-on: ubuntu-latest + if: ${{ github.event.release.prerelease == false }} steps: - uses: actions/checkout@v3 - name: Set version From 8fad9ced59e3836795508948a64d8e72548616e7 Mon Sep 17 00:00:00 2001 From: JupiterPi Date: Sun, 19 Jan 2025 18:47:12 +0100 Subject: [PATCH 08/15] fix: make FILEN_CLI_CRYPTO_BASE_KEY available in workflow --- .github/workflows/build-and-publish.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-and-publish.yml b/.github/workflows/build-and-publish.yml index ef4061a..c01a1ff 100644 --- a/.github/workflows/build-and-publish.yml +++ b/.github/workflows/build-and-publish.yml @@ -77,6 +77,7 @@ jobs: - run: npm ci - run: npm publish # includes build env: + FILEN_CLI_CRYPTO_BASE_KEY: ${{ secrets.FILEN_CLI_CRYPTO_BASE_KEY }} FILEN_IS_NPM_PACKAGE: true build-and-publish-docker: From 68423b122a3084497e24d4c60fdcca07e7723f2f Mon Sep 17 00:00:00 2001 From: JupiterPi Date: Sun, 19 Jan 2025 18:50:04 +0100 Subject: [PATCH 09/15] fix: proper NPM auth --- .github/workflows/build-and-publish.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-and-publish.yml b/.github/workflows/build-and-publish.yml index c01a1ff..a1800f9 100644 --- a/.github/workflows/build-and-publish.yml +++ b/.github/workflows/build-and-publish.yml @@ -75,10 +75,11 @@ jobs: with: node-version: "20.x" - run: npm ci - - run: npm publish # includes build + - run: npm publish --access public # includes build env: FILEN_CLI_CRYPTO_BASE_KEY: ${{ secrets.FILEN_CLI_CRYPTO_BASE_KEY }} FILEN_IS_NPM_PACKAGE: true + NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }} build-and-publish-docker: name: Build docker image From 9447976a870ff8782ee7f338a81c97f27a923de6 Mon Sep 17 00:00:00 2001 From: JupiterPi Date: Sun, 19 Jan 2025 19:03:13 +0100 Subject: [PATCH 10/15] fix: proper NPM auth --- .github/workflows/build-and-publish.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-and-publish.yml b/.github/workflows/build-and-publish.yml index a1800f9..6307998 100644 --- a/.github/workflows/build-and-publish.yml +++ b/.github/workflows/build-and-publish.yml @@ -74,6 +74,7 @@ jobs: uses: actions/setup-node@v4 with: node-version: "20.x" + registry-url: "https://registry.npmjs.org" - run: npm ci - run: npm publish --access public # includes build env: From aa05efc33b59ac56bfdc194b433b664727e1211b Mon Sep 17 00:00:00 2001 From: JupiterPi Date: Sun, 19 Jan 2025 19:09:27 +0100 Subject: [PATCH 11/15] fix: check for updates of @filen/cli --- src/updater.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/updater.ts b/src/updater.ts index 757e7f2..f3360e4 100644 --- a/src/updater.ts +++ b/src/updater.ts @@ -132,7 +132,7 @@ export class Updater { private async checkNPMRegistryForUpdates() { try { - const response = await fetch("https://registry.npmjs.org/filen-cli") + const response = await fetch("https://registry.npmjs.org/@filen/cli") if (response.status !== 200) throw new Error(`NPM registry API returned status ${response.status} ${response.statusText}`) const data = await response.json() From ae500be36d1fdcddeec8045c84c02a8fdf74071d Mon Sep 17 00:00:00 2001 From: JupiterPi Date: Sun, 19 Jan 2025 19:29:41 +0100 Subject: [PATCH 12/15] fix: properly run NPM registry update checker --- src/updater.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/updater.ts b/src/updater.ts index f3360e4..2ee9632 100644 --- a/src/updater.ts +++ b/src/updater.ts @@ -36,6 +36,11 @@ export class Updater { * @param autoUpdate the `--auto-update` CLI argument */ public async checkForUpdates(forceUpdateCheck: boolean, autoUpdate: boolean): Promise { + if (isRunningAsNPMPackage) { + await this.checkNPMRegistryForUpdates() + return + } + if ((process.pkg === undefined ? __filename : process.argv[0]!).endsWith(".js")) { outVerbose("Skipping updates for non-binary installation") return @@ -46,12 +51,6 @@ export class Updater { return } - // check NPM registry instead if running as NPM package - if (isRunningAsNPMPackage) { - await this.checkNPMRegistryForUpdates() - return - } - const updateCache = await this.readUpdateCache() // skip if already recently checked @@ -140,6 +139,8 @@ export class Updater { if (latestVersion === undefined) throw new Error("latest version not found in NPM registry response") if (latestVersion !== version) { out(`Update available: ${version} -> ${latestVersion} (install via npm i -g @filen/cli@latest)`) + } else { + outVerbose(`${version} is up to date.`) } } catch (e) { errExit("check NPM registry for updates", e) From 6038e31d48c385574dac3e113f97217244256b90 Mon Sep 17 00:00:00 2001 From: JupiterPi Date: Sun, 19 Jan 2025 19:34:36 +0100 Subject: [PATCH 13/15] fix: use semver.neq() for NPM registry update checker --- src/updater.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/updater.ts b/src/updater.ts index 2ee9632..686c0f6 100644 --- a/src/updater.ts +++ b/src/updater.ts @@ -137,8 +137,8 @@ export class Updater { const latestVersion = data["dist-tags"]["latest"] if (latestVersion === undefined) throw new Error("latest version not found in NPM registry response") - if (latestVersion !== version) { - out(`Update available: ${version} -> ${latestVersion} (install via npm i -g @filen/cli@latest)`) + if (semver.neq(latestVersion, version)) { + out(`Update available: ${version} -> v${latestVersion} (install via npm i -g @filen/cli@latest)`) } else { outVerbose(`${version} is up to date.`) } From ea8c2b8ef7097c96967a31d492b51065075902a1 Mon Sep 17 00:00:00 2001 From: JupiterPi Date: Mon, 20 Jan 2025 17:14:16 +0100 Subject: [PATCH 14/15] fix: don't run build-and-publish-npm workflow for prerelease releases --- .github/workflows/build-and-publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-publish.yml b/.github/workflows/build-and-publish.yml index 6307998..4ceb145 100644 --- a/.github/workflows/build-and-publish.yml +++ b/.github/workflows/build-and-publish.yml @@ -60,7 +60,7 @@ jobs: build-and-publish-npm: name: Build and publish to npm runs-on: ubuntu-latest - #todo: if: ${{ github.event.release.prerelease == false }} + if: ${{ github.event.release.prerelease == false }} steps: - name: Checkout uses: actions/checkout@v3 From 62d21cdedc6ce2ae4a01733658a49f3dc77bc4ab Mon Sep 17 00:00:00 2001 From: JupiterPi Date: Mon, 20 Jan 2025 17:29:32 +0100 Subject: [PATCH 15/15] docs: install script --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index caec399..2782ac7 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,11 @@ The Filen CLI provides a set of useful tools for interacting with the cloud: # Installation and updates -You can download the latest binaries from the [release page](https://github.com/FilenCloudDienste/filen-cli/releases/latest). +You can download the latest binaries from the [release page](https://github.com/FilenCloudDienste/filen-cli/releases/latest), or execute the install script (Linux and macOS): +```console +curl -s https://raw.githubusercontent.com/FilenCloudDienste/filen-cli/refs/heads/main/install.sh | bash +``` + Docker images are also available as [filen/cli](https://hub.docker.com/repository/docker/filen/cli) (see [below](#using-docker)). The Filen CLI includes an automatic updater that checks for a new release every time the CLI is invoked