Skip to content

Commit

Permalink
Merge pull request #254 from FilenCloudDienste/dev/install-script
Browse files Browse the repository at this point in the history
Install script and NPM package
  • Loading branch information
JupiterPi authored Jan 20, 2025
2 parents 61bbb4b + da0d9cb commit 9ed9251
Show file tree
Hide file tree
Showing 11 changed files with 184 additions and 37 deletions.
26 changes: 26 additions & 0 deletions .github/workflows/build-and-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,35 @@ 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
if: ${{ github.event.release.prerelease == false }}
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"
registry-url: "https://registry.npmjs.org"
- run: npm ci
- 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
runs-on: ubuntu-latest
if: ${{ github.event.release.prerelease == false }}
steps:
- uses: actions/checkout@v3
- name: Set version
Expand Down
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -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": {
Expand Down
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -26,6 +30,8 @@ Use the `--auto-update` flag to skip the confirmation prompt and update automati

You can always install any version using `filen install <version>`, `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,
Expand Down
2 changes: 2 additions & 0 deletions injectBuildInfo.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ 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"
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 => {
Expand Down
60 changes: 60 additions & 0 deletions install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/usr/bin/env bash

# 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 <version>\` 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
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 == *$(echo ~)/\.filen-cli* ]] ; then
echo "\$PATH already contains ~/.filen-cli"
else
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 your shell profile(s)"

fi
35 changes: 20 additions & 15 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 8 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "filen-cli",
"name": "@filen/cli",
"version": "0.0.0",
"description": "Filen CLI",
"main": "build/index.js",
Expand All @@ -12,8 +12,13 @@
"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"
},
"files": [ "build" ],
"engines": {
"node": "20"
},
Expand All @@ -28,7 +33,7 @@
"license": "AGPLv3",
"dependencies": {
"@filen/network-drive": "^0.9.40",
"@filen/s3": "^0.2.50",
"@filen/s3": "^0.2.51",
"@filen/sdk": "^0.1.192",
"@filen/sync": "^0.1.96",
"@filen/webdav": "^0.2.64",
Expand Down
4 changes: 4 additions & 0 deletions src/buildInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}}"
}
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#!/usr/bin/env node

import arg from "arg"
import FilenSDK from "@filen/sdk"
import path from "path"
Expand Down
31 changes: 30 additions & 1 deletion src/updater.ts
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -36,6 +36,16 @@ export class Updater {
* @param autoUpdate the `--auto-update` CLI argument
*/
public async checkForUpdates(forceUpdateCheck: boolean, autoUpdate: boolean): Promise<void> {
if (isRunningAsNPMPackage) {
await this.checkNPMRegistryForUpdates()
return
}

if ((process.pkg === undefined ? __filename : process.argv[0]!).endsWith(".js")) {
outVerbose("Skipping updates for non-binary installation")
return
}

if (version === "0.0.0") {
outVerbose("Skipping updates in development environment")
return
Expand Down Expand Up @@ -119,6 +129,24 @@ 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 (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.`)
}
} catch (e) {
errExit("check NPM registry for updates", e)
}
}

/**
* Shows a prompt to the user to enable or disable canary releases.
*/
Expand Down Expand Up @@ -260,6 +288,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...")
Expand Down
Loading

0 comments on commit 9ed9251

Please sign in to comment.