Merge branch 'release/v0.1.10'
This commit is contained in:
commit
e9553e278b
15 changed files with 508 additions and 99 deletions
58
.drone.yml
58
.drone.yml
|
@ -5,7 +5,7 @@ name: default
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: build:binary
|
- name: build:binary
|
||||||
image: crystallang/crystal:1.7.3
|
image: crystallang/crystal:1.10.1-alpine
|
||||||
environment:
|
environment:
|
||||||
PACKAGE_BASENAME: mfm_linux_amd64
|
PACKAGE_BASENAME: mfm_linux_amd64
|
||||||
volumes:
|
volumes:
|
||||||
|
@ -13,19 +13,27 @@ steps:
|
||||||
path: /_cache
|
path: /_cache
|
||||||
commands:
|
commands:
|
||||||
- pwd
|
- pwd
|
||||||
- apt-get update &&
|
# - |
|
||||||
apt-get install -y cmake g++ libevent-dev libpcre3-dev libyaml-dev
|
# apt-get update && \
|
||||||
|
# apt-get install -y \
|
||||||
|
# cmake g++ \
|
||||||
|
# libevent-dev libpcre3-dev \
|
||||||
|
# libyaml-dev liblzma-dev
|
||||||
- shards install
|
- shards install
|
||||||
- shards build --production --static
|
- shards build --production --static
|
||||||
- strip bin/mfm
|
- strip bin/mfm
|
||||||
|
- ./bin/mfm --version
|
||||||
- mkdir -p /_cache/bin
|
- mkdir -p /_cache/bin
|
||||||
- cp -r bin/mfm /_cache/bin/$PACKAGE_BASENAME
|
- cp -r bin/mfm /_cache/bin/$PACKAGE_BASENAME
|
||||||
|
|
||||||
- name: publish:tag
|
- name: publish:tag
|
||||||
image: curlimages/curl
|
image: alpine
|
||||||
environment:
|
environment:
|
||||||
PACKAGE_UPLOAD_URL: https://code.apps.glenux.net/api/packages/glenux/generic/mfm
|
PACKAGE_UPLOAD_URL: https://code.apps.glenux.net/api/v1/packages/glenux/generic/mfm
|
||||||
|
RELEASES_URL: https://code.apps.glenux.net/api/v1/repos/glenux/mfm/releases
|
||||||
PACKAGE_BASENAME: mfm_linux_amd64
|
PACKAGE_BASENAME: mfm_linux_amd64
|
||||||
|
RELEASE_UPLOAD_TOKEN:
|
||||||
|
from_secret: RELEASE_UPLOAD_TOKEN
|
||||||
PACKAGE_UPLOAD_TOKEN:
|
PACKAGE_UPLOAD_TOKEN:
|
||||||
from_secret: PACKAGE_UPLOAD_TOKEN
|
from_secret: PACKAGE_UPLOAD_TOKEN
|
||||||
when:
|
when:
|
||||||
|
@ -36,16 +44,52 @@ steps:
|
||||||
- name: cache
|
- name: cache
|
||||||
path: /_cache
|
path: /_cache
|
||||||
commands:
|
commands:
|
||||||
|
- apk add --update --no-cache curl jq
|
||||||
- env |grep DRONE
|
- env |grep DRONE
|
||||||
- |
|
- |
|
||||||
curl -H "Authorization: token $PACKAGE_UPLOAD_TOKEN" \
|
curl -H "Authorization: token $PACKAGE_UPLOAD_TOKEN" \
|
||||||
--upload-file /_cache/bin/$PACKAGE_BASENAME \
|
--upload-file "/_cache/bin/$PACKAGE_BASENAME" \
|
||||||
$PACKAGE_UPLOAD_URL/$DRONE_TAG/$PACKAGE_BASENAME
|
"$PACKAGE_UPLOAD_URL/$DRONE_TAG/$PACKAGE_BASENAME"
|
||||||
|
- |
|
||||||
|
set -x
|
||||||
|
curl -X POST \
|
||||||
|
-H "Authorization: token $RELEASE_UPLOAD_TOKEN" \
|
||||||
|
-H 'accept: application/json' \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d "{\"body\": \"DRAFT\", \"draft\": true, \"name\": \"$DRONE_TAG - DRAFT\", \"prerelease\": false, \"tag_name\": \"$DRONE_TAG\", \"target_commitish\": \"$DRONE_COMMIT_SHA\"}" \
|
||||||
|
"$RELEASES_URL"
|
||||||
|
- |
|
||||||
|
curl -X 'GET' \
|
||||||
|
-H 'accept: application/json' \
|
||||||
|
"$RELEASES_URL/tags/$DRONE_TAG"
|
||||||
|
- |
|
||||||
|
TAG_ID="$(curl -X 'GET' \
|
||||||
|
-H 'accept: application/json' \
|
||||||
|
"$RELEASES_URL/tags/$DRONE_TAG" | jq -r .id)"
|
||||||
|
echo "TAG_ID=$TAG_ID"
|
||||||
|
- |
|
||||||
|
set -x
|
||||||
|
curl -X POST \
|
||||||
|
-H "Authorization: token $RELEASE_UPLOAD_TOKEN" \
|
||||||
|
-H "accept: application/json" \
|
||||||
|
-H "Content-Type: multipart/form-data" \
|
||||||
|
-F "attachment=@/_cache/bin/$PACKAGE_BASENAME" \
|
||||||
|
"$RELEASES_URL/$TAG_ID/assets?name=$PACKAGE_BASENAME"
|
||||||
|
|
||||||
|
|
||||||
# FIXME: handle multi-arch
|
# FIXME: handle multi-arch
|
||||||
# FIXME: publish only on tags
|
# FIXME: publish only on tags
|
||||||
|
services:
|
||||||
|
- name: docker
|
||||||
|
image: docker:dind
|
||||||
|
privileged: true
|
||||||
|
volumes:
|
||||||
|
- name: dockersock
|
||||||
|
path: /var/run
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
- name: cache
|
- name: cache
|
||||||
temp: {}
|
temp: {}
|
||||||
|
- name: dockersock
|
||||||
|
temp: {}
|
||||||
#
|
#
|
||||||
|
|
30
README.md
30
README.md
|
@ -5,6 +5,8 @@
|
||||||
# Copyright © 2023 Glenn Y. Rolland <glenux@glenux.net>
|
# Copyright © 2023 Glenn Y. Rolland <glenux@glenux.net>
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
[![Build Status](https://cicd.apps.glenux.net/api/badges/glenux/mfm/status.svg)](https://cicd.apps.glenux.net/glenux/mfm)
|
||||||
|
|
||||||
# Minimalist Fuse Manager (MFM)
|
# Minimalist Fuse Manager (MFM)
|
||||||
|
|
||||||
MFM is a Crystal-lang CLI designed to streamline the management of various FUSE filesystems, such as sshfs, gocryptfs, httpdirfs, and more. Through its user-friendly interface, users can effortlessly mount and unmount filesystems, get real-time filesystem status, and handle errors proficiently.
|
MFM is a Crystal-lang CLI designed to streamline the management of various FUSE filesystems, such as sshfs, gocryptfs, httpdirfs, and more. Through its user-friendly interface, users can effortlessly mount and unmount filesystems, get real-time filesystem status, and handle errors proficiently.
|
||||||
|
@ -17,11 +19,27 @@ Before using MFM, make sure the following tools are installed on your system:
|
||||||
- **sshfs**: <https://github.com/libfuse/sshfs>
|
- **sshfs**: <https://github.com/libfuse/sshfs>
|
||||||
- **httpdirfs**: <https://github.com/fangfufu/httpdirfs>
|
- **httpdirfs**: <https://github.com/fangfufu/httpdirfs>
|
||||||
- **fzf**: <https://github.com/junegunn/fzf>
|
- **fzf**: <https://github.com/junegunn/fzf>
|
||||||
|
- libpcre3
|
||||||
|
- libevent-2.1
|
||||||
|
|
||||||
|
For Debian/Ubuntu you can use the following command:
|
||||||
|
|
||||||
|
```shell-session
|
||||||
|
$ sudo apt-get update && sudo apt-get install libpcre3 libevent-2.1-7 fzf gocryptfs httpdirfs sshfs
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building from source
|
||||||
|
|
||||||
To build from source, you'll also need:
|
To build from source, you'll also need:
|
||||||
|
|
||||||
- **crystal-lang**: <https://crystal-lang.org/>
|
- **crystal-lang**: <https://crystal-lang.org/>
|
||||||
|
|
||||||
|
For Debian/Ubuntu you can use the following command:
|
||||||
|
|
||||||
|
```shell-session
|
||||||
|
$ sudo apt-get update && sudo apt-get install libpcre3-dev libevent-2.1-dev
|
||||||
|
```
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### 1. From Source
|
### 1. From Source
|
||||||
|
@ -34,7 +52,8 @@ To build from source, you'll also need:
|
||||||
|
|
||||||
### 2. Binary Download
|
### 2. Binary Download
|
||||||
|
|
||||||
Alternatively, download a pre-compiled binary version of MFM.
|
Alternatively, download [a pre-compiled binary
|
||||||
|
version](https://code.apps.glenux.net/glenux/mfm/releases) of MFM.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
@ -47,7 +66,7 @@ Global options:
|
||||||
-c, --config FILE Specify configuration file
|
-c, --config FILE Specify configuration file
|
||||||
-h, --help Display this help
|
-h, --help Display this help
|
||||||
|
|
||||||
Commands:
|
Commands (not implemented yet):
|
||||||
create Add a new filesystem
|
create Add a new filesystem
|
||||||
delete Remove an existing filesystem
|
delete Remove an existing filesystem
|
||||||
edit Modify the configuration
|
edit Modify the configuration
|
||||||
|
@ -59,7 +78,8 @@ Commands:
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
MFM uses a YAML configuration file, typically found at `~/.config/mfm.yml`, to detail the filesystem names, types, and respective configurations.
|
MFM uses a YAML configuration file, typically found at `~/.config/mfm.yml`, to
|
||||||
|
detail the filesystem names, types, and respective configurations.
|
||||||
|
|
||||||
### YAML File Format
|
### YAML File Format
|
||||||
|
|
||||||
|
@ -84,7 +104,7 @@ filesystems:
|
||||||
- type: httpdirfs
|
- type: httpdirfs
|
||||||
name: "Debian Repository"
|
name: "Debian Repository"
|
||||||
url: "http://ftp.debian.org/debian/"
|
url: "http://ftp.debian.org/debian/"
|
||||||
|
|
||||||
# Add more filesystems as needed
|
# Add more filesystems as needed
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -100,7 +120,7 @@ Contributing to MFM:
|
||||||
6. **Submit a Pull Request**: Begin a pull request to the main repository and explain your changes.
|
6. **Submit a Pull Request**: Begin a pull request to the main repository and explain your changes.
|
||||||
7. **Review**: Await feedback from the maintainers and respond as necessary.
|
7. **Review**: Await feedback from the maintainers and respond as necessary.
|
||||||
|
|
||||||
By contributing, you agree to our code of conduct and GPL-2 license terms.
|
By contributing, you agree to our code of conduct and license terms.
|
||||||
|
|
||||||
## Authors and Contributors
|
## Authors and Contributors
|
||||||
|
|
||||||
|
|
2
Vagrantfile
vendored
2
Vagrantfile
vendored
|
@ -30,5 +30,5 @@ Vagrant.configure('2') do |config|
|
||||||
machine.vm.network 'forwarded_port', guest: 80, host: 1080, host_ip: '127.0.0.1'
|
machine.vm.network 'forwarded_port', guest: 80, host: 1080, host_ip: '127.0.0.1'
|
||||||
end
|
end
|
||||||
|
|
||||||
config.vm.provision 'shell', path: 'scripts/vagrant.provision.sh'
|
config.vm.provision 'shell', path: 'scripts/vagrant-provision/base.sh'
|
||||||
end
|
end
|
||||||
|
|
64
scripts/ci.crossbuild-alpine.sh
Executable file
64
scripts/ci.crossbuild-alpine.sh
Executable file
|
@ -0,0 +1,64 @@
|
||||||
|
#!/bin/sh -eu
|
||||||
|
# vim: set ts=2 sw=2 et:
|
||||||
|
|
||||||
|
LOCAL_PROJECT_PATH="${1-$PWD}"
|
||||||
|
|
||||||
|
TARGET_ARCH="${2-amd64}"
|
||||||
|
|
||||||
|
DOCKER_IMAGE=""
|
||||||
|
|
||||||
|
BUILD_COMMAND=" \
|
||||||
|
shards build --static --release \
|
||||||
|
&& chown 1000:1000 -R bin \
|
||||||
|
&& find bin -type f -maxdepth 1 -exec mv {} {}_${TARGET_ARCH} \; \
|
||||||
|
"
|
||||||
|
INSTALL_CRYSTAL=" \
|
||||||
|
echo '@edge http://dl-cdn.alpinelinux.org/alpine/edge/community' >>/etc/apk/repositories \
|
||||||
|
&& apk add --update --no-cache --force-overwrite \
|
||||||
|
crystal@edge \
|
||||||
|
g++ \
|
||||||
|
gc-dev \
|
||||||
|
libxml2-dev \
|
||||||
|
llvm16-dev \
|
||||||
|
llvm16-static \
|
||||||
|
make \
|
||||||
|
musl-dev \
|
||||||
|
openssl-dev \
|
||||||
|
openssl-libs-static \
|
||||||
|
pcre-dev \
|
||||||
|
shards@edge \
|
||||||
|
yaml-dev \
|
||||||
|
yaml-static \
|
||||||
|
zlib-dev \
|
||||||
|
zlib-static \
|
||||||
|
"
|
||||||
|
|
||||||
|
# setup arch
|
||||||
|
case "$TARGET_ARCH" in
|
||||||
|
amd64) DOCKER_IMAGE="alpine" ;;
|
||||||
|
arm64) DOCKER_IMAGE="multiarch/alpine:aarch64-edge" ;;
|
||||||
|
armel) DOCKER_IMAGE="multiarch/alpine:armv7-edge" ;;
|
||||||
|
# armhf) DOCKER_IMAGE="multiarch/alpine:armhf-edge" ;;
|
||||||
|
# i386) DOCKER_IMAGE="multiarch/alpine:x86-edge" ;;
|
||||||
|
mips) DOCKER_IMAGE="multiarch/alpine:mips-edge" ;;
|
||||||
|
mipsel) DOCKER_IMAGE="multiarch/alpine:mipsel-edge" ;;
|
||||||
|
powerpc) DOCKER_IMAGE="multiarch/alpine:powerpc-edge" ;;
|
||||||
|
ppc64el) DOCKER_IMAGE="multiarch/alpine:ppc64el-edge" ;;
|
||||||
|
s390x) DOCKER_IMAGE="multiarch/alpine:s390x-edge" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Compile Crystal project statically for target architecture
|
||||||
|
docker pull multiarch/qemu-user-static:register
|
||||||
|
docker run \
|
||||||
|
--rm \
|
||||||
|
--privileged \
|
||||||
|
multiarch/qemu-user-static:register \
|
||||||
|
--reset
|
||||||
|
docker run \
|
||||||
|
-it \
|
||||||
|
-v "$LOCAL_PROJECT_PATH:/app" \
|
||||||
|
-w /app \
|
||||||
|
--rm \
|
||||||
|
"$DOCKER_IMAGE" \
|
||||||
|
/bin/sh -c "$INSTALL_CRYSTAL && $BUILD_COMMAND"
|
||||||
|
|
82
scripts/ci.crossbuild-debian.sh
Executable file
82
scripts/ci.crossbuild-debian.sh
Executable file
|
@ -0,0 +1,82 @@
|
||||||
|
#!/bin/sh -eu
|
||||||
|
# vim: set ts=2 sw=2 et:
|
||||||
|
|
||||||
|
LOCAL_PROJECT_PATH="${1-$PWD}"
|
||||||
|
|
||||||
|
TARGET_ARCH="${2-amd64}"
|
||||||
|
|
||||||
|
DOCKER_IMAGE=""
|
||||||
|
|
||||||
|
BUILD_COMMAND=" \
|
||||||
|
shards build --static --release \
|
||||||
|
&& chown 1000:1000 -R bin \
|
||||||
|
&& find bin -type f -maxdepth 1 -exec mv {} {}_${TARGET_ARCH} \; \
|
||||||
|
"
|
||||||
|
|
||||||
|
# crystal
|
||||||
|
INSTALL_CRYSTAL=" \
|
||||||
|
sed -i -e 's/Types: deb/Types: deb deb-src/' /etc/apt/sources.list.d/debian.sources \
|
||||||
|
&& echo 'deb http://deb.debian.org/debian unstable main' > /etc/apt/sources.list.d/sid.list \
|
||||||
|
&& echo 'deb-src http://deb.debian.org/debian unstable main' >> /etc/apt/sources.list.d/sid.list \
|
||||||
|
&& apt-get update \
|
||||||
|
&& apt-get install -y \
|
||||||
|
g++ \
|
||||||
|
libxml2-dev \
|
||||||
|
llvm-dev \
|
||||||
|
make \
|
||||||
|
libssl-dev \
|
||||||
|
libpcre3-dev \
|
||||||
|
libyaml-dev \
|
||||||
|
zlib1g-dev \
|
||||||
|
dpkg-dev \
|
||||||
|
debuild \
|
||||||
|
&& apt source crystal \
|
||||||
|
&& apt build-dep crystal \
|
||||||
|
&& ls -lF \
|
||||||
|
&& debuild -b -uc -us \
|
||||||
|
"
|
||||||
|
|
||||||
|
# setup arch
|
||||||
|
case "$TARGET_ARCH" in
|
||||||
|
amd64) DOCKER_IMAGE="debian" ;;
|
||||||
|
arm64) DOCKER_IMAGE="arm64v8/debian" ;;
|
||||||
|
armel) DOCKER_IMAGE="arm32v7/debian" ;;
|
||||||
|
armhf) DOCKER_IMAGE="armhf/debian" ;;
|
||||||
|
i386) DOCKER_IMAGE="x86/debian" ;;
|
||||||
|
mips) DOCKER_IMAGE="mips/debian" ;;
|
||||||
|
mipsel) DOCKER_IMAGE="mipsel/debian" ;;
|
||||||
|
powerpc) DOCKER_IMAGE="powerpc/debian" ;;
|
||||||
|
ppc64el) DOCKER_IMAGE="ppc64el/debian" ;;
|
||||||
|
s390x) DOCKER_IMAGE="s390x/debian" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Compile Crystal project statically for target architecture
|
||||||
|
docker pull multiarch/qemu-user-static
|
||||||
|
|
||||||
|
docker run \
|
||||||
|
--rm \
|
||||||
|
--privileged \
|
||||||
|
multiarch/qemu-user-static \
|
||||||
|
--reset -p yes
|
||||||
|
|
||||||
|
set -x
|
||||||
|
docker run \
|
||||||
|
-it \
|
||||||
|
-v "$LOCAL_PROJECT_PATH:/app" \
|
||||||
|
-w /app \
|
||||||
|
--rm \
|
||||||
|
--platform linux/arm64 \
|
||||||
|
"$DOCKER_IMAGE"
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
||||||
|
set -x
|
||||||
|
docker run \
|
||||||
|
-it \
|
||||||
|
-v "$LOCAL_PROJECT_PATH:/app" \
|
||||||
|
-w /app \
|
||||||
|
--rm \
|
||||||
|
--platform linux/arm64 \
|
||||||
|
"$DOCKER_IMAGE" \
|
||||||
|
/bin/sh -c "$INSTALL_CRYSTAL && $BUILD_COMMAND"
|
||||||
|
|
86
scripts/compiler.crossbuild-debian.sh
Executable file
86
scripts/compiler.crossbuild-debian.sh
Executable file
|
@ -0,0 +1,86 @@
|
||||||
|
#!/bin/sh -eu
|
||||||
|
# vim: set ts=2 sw=2 et:
|
||||||
|
|
||||||
|
LOCAL_PROJECT_PATH="${1-$PWD}"
|
||||||
|
|
||||||
|
TARGET_ARCH="${2-arm64}"
|
||||||
|
|
||||||
|
DOCKER_IMAGE=""
|
||||||
|
|
||||||
|
BUILD_COMMAND=" \
|
||||||
|
shards build --static --release \
|
||||||
|
&& chown 1000:1000 -R bin \
|
||||||
|
&& find bin -type f -maxdepth 1 -exec mv {} {}_${TARGET_ARCH} \; \
|
||||||
|
"
|
||||||
|
|
||||||
|
# crystal
|
||||||
|
INSTALL_CRYSTAL=" \
|
||||||
|
sed -i -e '/^deb/d' /etc/apt/sources.list \
|
||||||
|
&& sed -i -e '/jessie.updates/d' /etc/apt/sources.list \
|
||||||
|
&& sed -i -e 's/^# deb/deb/' /etc/apt/sources.list \
|
||||||
|
&& apt-get update"
|
||||||
|
|
||||||
|
cat > /dev/null <<EOF
|
||||||
|
"
|
||||||
|
&& apt-get install -y \
|
||||||
|
g\+\+ \
|
||||||
|
gcc \
|
||||||
|
curl \
|
||||||
|
autoconf \
|
||||||
|
automake \
|
||||||
|
python2 \
|
||||||
|
libxml2-dev \
|
||||||
|
llvm-dev \
|
||||||
|
make \
|
||||||
|
libssl-dev \
|
||||||
|
libpcre2-dev \
|
||||||
|
libyaml-dev \
|
||||||
|
zlib1g-dev \
|
||||||
|
"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# setup arch
|
||||||
|
case "$TARGET_ARCH" in
|
||||||
|
amd64) DOCKER_IMAGE="debian:8" ;;
|
||||||
|
arm64) DOCKER_IMAGE="arm64v8/debian:8" ;;
|
||||||
|
armel) DOCKER_IMAGE="arm32v7/debian" ;;
|
||||||
|
armhf) DOCKER_IMAGE="armhf/debian" ;;
|
||||||
|
i386) DOCKER_IMAGE="x86/debian" ;;
|
||||||
|
mips) DOCKER_IMAGE="mips/debian" ;;
|
||||||
|
mipsel) DOCKER_IMAGE="mipsel/debian" ;;
|
||||||
|
powerpc) DOCKER_IMAGE="powerpc/debian" ;;
|
||||||
|
ppc64el) DOCKER_IMAGE="ppc64el/debian" ;;
|
||||||
|
s390x) DOCKER_IMAGE="s390x/debian" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Compile Crystal project statically for target architecture
|
||||||
|
docker pull multiarch/qemu-user-static
|
||||||
|
|
||||||
|
docker run \
|
||||||
|
--rm \
|
||||||
|
--privileged \
|
||||||
|
multiarch/qemu-user-static \
|
||||||
|
--reset -p yes
|
||||||
|
|
||||||
|
set -x
|
||||||
|
docker run \
|
||||||
|
-it \
|
||||||
|
-v "$LOCAL_PROJECT_PATH:/app" \
|
||||||
|
-w /app \
|
||||||
|
--rm \
|
||||||
|
--platform linux/arm64 \
|
||||||
|
"$DOCKER_IMAGE" \
|
||||||
|
/bin/sh -c "$INSTALL_CRYSTAL && bash"
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
||||||
|
set -x
|
||||||
|
docker run \
|
||||||
|
-it \
|
||||||
|
-v "$LOCAL_PROJECT_PATH:/app" \
|
||||||
|
-w /app \
|
||||||
|
--rm \
|
||||||
|
--platform linux/arm64 \
|
||||||
|
"$DOCKER_IMAGE" \
|
||||||
|
/bin/sh -c "$INSTALL_CRYSTAL && $BUILD_COMMAND"
|
||||||
|
|
32
scripts/vagrant-provision/base.sh
Normal file
32
scripts/vagrant-provision/base.sh
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
set -u
|
||||||
|
|
||||||
|
USER="$(test -d /vagrant && echo "vagrant" || echo "debian")"
|
||||||
|
HOSTNAME="$(hostname)"
|
||||||
|
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
echo "Installing required system packages"
|
||||||
|
apt-get update --allow-releaseinfo-change
|
||||||
|
apt-get install -y \
|
||||||
|
apt-transport-https \
|
||||||
|
ca-certificates \
|
||||||
|
git \
|
||||||
|
curl \
|
||||||
|
wget \
|
||||||
|
vim \
|
||||||
|
gnupg2 \
|
||||||
|
software-properties-common
|
||||||
|
|
||||||
|
# echo "Installing mfm requirements"
|
||||||
|
# apt-get install -y \
|
||||||
|
# fzf \
|
||||||
|
# sshfs \
|
||||||
|
# httpdirfs \
|
||||||
|
# libyaml-0-2 \
|
||||||
|
# libyaml-dev \
|
||||||
|
# libpcre3-dev \
|
||||||
|
# libevent-dev
|
||||||
|
|
|
@ -9,26 +9,6 @@ HOSTNAME="$(hostname)"
|
||||||
|
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
echo "Installing required system packages"
|
|
||||||
apt-get update --allow-releaseinfo-change
|
|
||||||
apt-get install -y \
|
|
||||||
apt-transport-https \
|
|
||||||
ca-certificates \
|
|
||||||
git \
|
|
||||||
curl \
|
|
||||||
wget \
|
|
||||||
vim \
|
|
||||||
gnupg2 \
|
|
||||||
software-properties-common
|
|
||||||
|
|
||||||
echo "Installing recording requirements"
|
|
||||||
apt-get install -y \
|
|
||||||
tmux \
|
|
||||||
mdp \
|
|
||||||
bat \
|
|
||||||
asciinema \
|
|
||||||
termtosvg
|
|
||||||
|
|
||||||
echo "Installing mfm requirements"
|
echo "Installing mfm requirements"
|
||||||
apt-get install -y \
|
apt-get install -y \
|
||||||
fzf \
|
fzf \
|
||||||
|
@ -39,24 +19,6 @@ apt-get install -y \
|
||||||
libpcre3-dev \
|
libpcre3-dev \
|
||||||
libevent-dev
|
libevent-dev
|
||||||
|
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
set -e
|
|
||||||
set -u
|
|
||||||
|
|
||||||
USER="$(test -d /vagrant && echo "vagrant" || echo "debian")"
|
|
||||||
CLUSTERS_DIR=/home/$USER/clusters
|
|
||||||
|
|
||||||
# Installation de kompose
|
|
||||||
if [ ! -f /usr/local/bin/kompose ]; then
|
|
||||||
DL="$(mktemp)"
|
|
||||||
curl \
|
|
||||||
-L https://github.com/kubernetes/kompose/releases/download/v1.22.0/kompose-linux-amd64 \
|
|
||||||
-o "$DL"
|
|
||||||
chmod +x "$DL"
|
|
||||||
mv "$DL" /usr/local/bin/kompose
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Installing asdf
|
# Installing asdf
|
||||||
su - "$USER" -c "git config --global advice.detachedHead false"
|
su - "$USER" -c "git config --global advice.detachedHead false"
|
||||||
su - "$USER" -c "rm -rf ~/.asdf"
|
su - "$USER" -c "rm -rf ~/.asdf"
|
22
scripts/vagrant-provision/recording.sh
Normal file
22
scripts/vagrant-provision/recording.sh
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# install crystal
|
||||||
|
set -e
|
||||||
|
set -u
|
||||||
|
|
||||||
|
USER="$(test -d /vagrant && echo "vagrant" || echo "debian")"
|
||||||
|
HOSTNAME="$(hostname)"
|
||||||
|
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
echo "Installing required system packages"
|
||||||
|
apt-get update --allow-releaseinfo-change
|
||||||
|
|
||||||
|
echo "Installing recording requirements"
|
||||||
|
apt-get install -y \
|
||||||
|
tmux \
|
||||||
|
mdp \
|
||||||
|
bat \
|
||||||
|
asciinema \
|
||||||
|
termtosvg
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
version: 2.0
|
version: 2.0
|
||||||
shards:
|
shards:
|
||||||
|
crinja:
|
||||||
|
git: https://github.com/straight-shoota/crinja.git
|
||||||
|
version: 0.8.1
|
||||||
|
|
||||||
shellwords:
|
shellwords:
|
||||||
git: https://github.com/sztheory/shellwords-crystal.git
|
git: https://github.com/sztheory/shellwords-crystal.git
|
||||||
version: 0.1.0
|
version: 0.1.0
|
||||||
|
|
|
@ -18,6 +18,8 @@ targets:
|
||||||
# Short description of gx-vault
|
# Short description of gx-vault
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
|
crinja:
|
||||||
|
github: straight-shoota/crinja
|
||||||
shellwords:
|
shellwords:
|
||||||
github: szTheory/shellwords-crystal
|
github: szTheory/shellwords-crystal
|
||||||
|
|
||||||
|
|
95
src/cli.cr
95
src/cli.cr
|
@ -8,7 +8,10 @@ require "./config"
|
||||||
require "./fzf"
|
require "./fzf"
|
||||||
|
|
||||||
module GX
|
module GX
|
||||||
|
VERSION="v0.1.9"
|
||||||
|
|
||||||
class Cli
|
class Cli
|
||||||
|
Log = ::Log.for("cli")
|
||||||
|
|
||||||
@config : Config
|
@config : Config
|
||||||
|
|
||||||
|
@ -27,65 +30,87 @@ module GX
|
||||||
parser.banner = "Usage: #{PROGRAM_NAME} [options]\n\nGlobal options"
|
parser.banner = "Usage: #{PROGRAM_NAME} [options]\n\nGlobal options"
|
||||||
|
|
||||||
parser.on("-c", "--config FILE", "Set configuration file") do |path|
|
parser.on("-c", "--config FILE", "Set configuration file") do |path|
|
||||||
|
Log.info { "Configuration set to #{path}" }
|
||||||
@config.path = path
|
@config.path = path
|
||||||
end
|
end
|
||||||
|
|
||||||
|
parser.on("-v", "--verbose", "Set more verbosity") do |flag|
|
||||||
|
Log.info { "Verbosity enabled" }
|
||||||
|
@config.verbose = true
|
||||||
|
end
|
||||||
|
|
||||||
|
parser.on("--version", "Show version") do |flag|
|
||||||
|
@config.mode = Config::Mode::ShowVersion
|
||||||
|
end
|
||||||
|
|
||||||
parser.on("-h", "--help", "Show this help") do |flag|
|
parser.on("-h", "--help", "Show this help") do |flag|
|
||||||
STDOUT.puts parser
|
STDOUT.puts parser
|
||||||
exit(0)
|
exit(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
parser.separator("\nCommands")
|
parser.separator("\nCommands")
|
||||||
parser.on("create", "Create vault") do
|
parser.on("config", "Manage configuration") do
|
||||||
@config.mode = Config::Mode::Add
|
parser.banner = "Usage: #{PROGRAM_NAME} config [commands] [options]\n\nGlobal options"
|
||||||
|
parser.separator("\nCommands")
|
||||||
|
|
||||||
parser.banner = "Usage: #{PROGRAM_NAME} create [options]\n\nGlobal options"
|
parser.on("create", "Create vault") do
|
||||||
parser.separator("\nCommand options")
|
@config.mode = Config::Mode::ConfigAdd
|
||||||
|
|
||||||
parser.on("-n", "--name", "Set vault name") do |name|
|
parser.banner = "Usage: #{PROGRAM_NAME} config create [commands] [options]\n\nGlobal options"
|
||||||
add_args = add_args.merge({ name: name })
|
parser.separator("\nCommand options")
|
||||||
|
|
||||||
|
parser.on("-n", "--name", "Set vault name") do |name|
|
||||||
|
add_args = add_args.merge({ name: name })
|
||||||
|
end
|
||||||
|
parser.on("-p", "--path", "Set vault encrypted path") do |path|
|
||||||
|
add_args = add_args.merge({ path: path })
|
||||||
|
end
|
||||||
end
|
end
|
||||||
parser.on("-p", "--path", "Set vault encrypted path") do |path|
|
|
||||||
add_args = add_args.merge({ path: path })
|
parser.on("delete", "Delete vault") do
|
||||||
|
@config.mode = Config::Mode::ConfigAdd
|
||||||
|
|
||||||
|
parser.banner = "Usage: #{PROGRAM_NAME} delete [options]\n\nGlobal options"
|
||||||
|
parser.separator("\nCommand options")
|
||||||
|
|
||||||
|
parser.on("-n", "--name", "Set vault name") do |name|
|
||||||
|
delete_args = delete_args.merge({ name: name })
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
parser.on("delete", "Delete vault") do
|
parser.on("edit", "Edit configuration") do |flag|
|
||||||
@config.mode = Config::Mode::Add
|
@config.mode = Config::Mode::ConfigEdit
|
||||||
|
|
||||||
parser.banner = "Usage: #{PROGRAM_NAME} delete [options]\n\nGlobal options"
|
|
||||||
parser.separator("\nCommand options")
|
|
||||||
|
|
||||||
parser.on("-n", "--name", "Set vault name") do |name|
|
|
||||||
delete_args = delete_args.merge({ name: name })
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
parser.on("edit", "Edit configuration") do |flag|
|
|
||||||
@config.mode = Config::Mode::Edit
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
pparser.parse(args)
|
pparser.parse(args)
|
||||||
end
|
end
|
||||||
|
|
||||||
def run()
|
def run()
|
||||||
@config.load_from_file
|
case @config.mode
|
||||||
|
when Config::Mode::ShowVersion
|
||||||
|
STDOUT.puts "#{PROGRAM_NAME} #{VERSION}"
|
||||||
|
when Config::Mode::Mount
|
||||||
|
@config.load_from_file
|
||||||
|
mount
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def mount()
|
||||||
names_display = {} of String => NamedTuple(filesystem: Filesystem, ansi_name: String)
|
names_display = {} of String => NamedTuple(filesystem: Filesystem, ansi_name: String)
|
||||||
@config.filesystems.each do |filesystem|
|
@config.filesystems.each do |filesystem|
|
||||||
fs_str = filesystem.type.ljust(12,' ')
|
fs_str = filesystem.type.ljust(12,' ')
|
||||||
result_name =
|
|
||||||
if filesystem.mounted?
|
suffix = ""
|
||||||
"#{fs_str} #{filesystem.name} [open]"
|
suffix_ansi = ""
|
||||||
else
|
if filesystem.mounted?
|
||||||
"#{fs_str} #{filesystem.name}"
|
suffix = "[open]"
|
||||||
end
|
suffix_ansi = "[#{ "open".colorize(:green) }]"
|
||||||
ansi_name =
|
end
|
||||||
if filesystem.mounted?
|
|
||||||
"#{fs_str.colorize(:dark_gray)} #{filesystem.name} [#{ "open".colorize(:green) }]"
|
result_name = "#{fs_str} #{filesystem.name} #{suffix}".strip
|
||||||
else
|
ansi_name = "#{fs_str.colorize(:dark_gray)} #{filesystem.name} #{suffix_ansi}".strip
|
||||||
"#{fs_str.colorize(:dark_gray)} #{filesystem.name}"
|
|
||||||
end
|
|
||||||
|
|
||||||
names_display[result_name] = {
|
names_display[result_name] = {
|
||||||
filesystem: filesystem,
|
filesystem: filesystem,
|
||||||
|
@ -93,7 +118,7 @@ module GX
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
result_filesystem_name = Fzf.run(names_display.values.map(&.[:ansi_name]).sort)
|
result_filesystem_name = Fzf.run(names_display.values.map(&.[:ansi_name]).sort).strip
|
||||||
selected_filesystem = names_display[result_filesystem_name][:filesystem]
|
selected_filesystem = names_display[result_filesystem_name][:filesystem]
|
||||||
puts ">> #{selected_filesystem.name}".colorize(:yellow)
|
puts ">> #{selected_filesystem.name}".colorize(:yellow)
|
||||||
|
|
||||||
|
|
|
@ -3,14 +3,20 @@
|
||||||
# SPDX-FileCopyrightText: 2023 Glenn Y. Rolland <glenux@glenux.net>
|
# SPDX-FileCopyrightText: 2023 Glenn Y. Rolland <glenux@glenux.net>
|
||||||
# Copyright © 2023 Glenn Y. Rolland <glenux@glenux.net>
|
# Copyright © 2023 Glenn Y. Rolland <glenux@glenux.net>
|
||||||
|
|
||||||
|
require "crinja"
|
||||||
|
|
||||||
require "./filesystems"
|
require "./filesystems"
|
||||||
|
|
||||||
module GX
|
module GX
|
||||||
class Config
|
class Config
|
||||||
|
Log = ::Log.for("config")
|
||||||
|
|
||||||
enum Mode
|
enum Mode
|
||||||
Add
|
ConfigAdd
|
||||||
Edit
|
ConfigDelete
|
||||||
Run
|
ConfigEdit
|
||||||
|
ShowVersion
|
||||||
|
Mount
|
||||||
end
|
end
|
||||||
|
|
||||||
record NoArgs
|
record NoArgs
|
||||||
|
@ -19,36 +25,69 @@ module GX
|
||||||
|
|
||||||
getter filesystems : Array(Filesystem)
|
getter filesystems : Array(Filesystem)
|
||||||
getter home_dir : String
|
getter home_dir : String
|
||||||
|
property verbose : Bool
|
||||||
property mode : Mode
|
property mode : Mode
|
||||||
property path : String
|
property path : String?
|
||||||
property args : AddArgs.class | DelArgs.class | NoArgs.class
|
property args : AddArgs.class | DelArgs.class | NoArgs.class
|
||||||
|
|
||||||
DEFAULT_CONFIG_PATH = "mfm.yml"
|
|
||||||
|
|
||||||
def initialize()
|
def initialize()
|
||||||
if !ENV["HOME"]?
|
if !ENV["HOME"]?
|
||||||
raise "Home directory not found"
|
raise "Home directory not found"
|
||||||
end
|
end
|
||||||
@home_dir = ENV["HOME"]
|
@home_dir = ENV["HOME"]
|
||||||
|
|
||||||
@mode = Mode::Run
|
@verbose = false
|
||||||
|
@mode = Mode::Mount
|
||||||
@filesystems = [] of Filesystem
|
@filesystems = [] of Filesystem
|
||||||
@path = File.join(@home_dir, ".config", DEFAULT_CONFIG_PATH)
|
@path = nil
|
||||||
|
|
||||||
@args = NoArgs
|
@args = NoArgs
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def detect_config_file()
|
||||||
|
possible_files = [
|
||||||
|
File.join(@home_dir, ".config", "mfm", "config.yaml"),
|
||||||
|
File.join(@home_dir, ".config", "mfm", "config.yml"),
|
||||||
|
File.join(@home_dir, ".config", "mfm.yaml"),
|
||||||
|
File.join(@home_dir, ".config", "mfm.yml"),
|
||||||
|
File.join("/etc", "mfm", "config.yaml"),
|
||||||
|
File.join("/etc", "mfm", "config.yml"),
|
||||||
|
]
|
||||||
|
|
||||||
|
possible_files.each do |file_path|
|
||||||
|
if File.exists?(file_path)
|
||||||
|
Log.info { "Configuration file found: #{file_path}" }
|
||||||
|
return file_path if File.exists?(file_path)
|
||||||
|
else
|
||||||
|
Log.debug { "Configuration file not found: #{file_path}" }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Log.error { "No configuration file found in any of the standard locations" }
|
||||||
|
raise "Configuration file not found"
|
||||||
|
end
|
||||||
|
|
||||||
def load_from_file
|
def load_from_file
|
||||||
|
path = @path
|
||||||
|
if path.nil?
|
||||||
|
path = detect_config_file()
|
||||||
|
end
|
||||||
|
@path = path
|
||||||
@filesystems = [] of Filesystem
|
@filesystems = [] of Filesystem
|
||||||
|
|
||||||
if !File.exists? @path
|
if !File.exists? path
|
||||||
STDERR.puts "Error: file #{@path} does not exist!".colorize(:red)
|
Log.error { "File #{path} does not exist!".colorize(:red) }
|
||||||
exit(1)
|
exit(1)
|
||||||
end
|
end
|
||||||
load_filesystems(@path)
|
load_filesystems(path)
|
||||||
end
|
end
|
||||||
|
|
||||||
private def load_filesystems(config_path : String)
|
private def load_filesystems(config_path : String)
|
||||||
yaml_data = YAML.parse(File.read(config_path))
|
file_data = File.read(config_path)
|
||||||
|
# FIXME: render template on a value basis (instead of global)
|
||||||
|
file_patched = Crinja.render(file_data, {"env" => ENV.to_h})
|
||||||
|
|
||||||
|
yaml_data = YAML.parse(file_patched)
|
||||||
vaults_data = yaml_data["filesystems"].as_a
|
vaults_data = yaml_data["filesystems"].as_a
|
||||||
|
|
||||||
vaults_data.each do |filesystem_data|
|
vaults_data.each do |filesystem_data|
|
||||||
|
|
|
@ -12,6 +12,7 @@ module GX
|
||||||
getter remote_path : String = ""
|
getter remote_path : String = ""
|
||||||
getter remote_user : String = ""
|
getter remote_user : String = ""
|
||||||
getter remote_host : String = ""
|
getter remote_host : String = ""
|
||||||
|
getter remote_port : String = "22"
|
||||||
|
|
||||||
@[YAML::Field(key: "mount_dir", ignore: true)]
|
@[YAML::Field(key: "mount_dir", ignore: true)]
|
||||||
getter mount_dir : String = ""
|
getter mount_dir : String = ""
|
||||||
|
@ -34,7 +35,11 @@ module GX
|
||||||
error = STDERR
|
error = STDERR
|
||||||
process = Process.new(
|
process = Process.new(
|
||||||
"sshfs",
|
"sshfs",
|
||||||
["#{remote_user}@#{remote_host}:#{remote_path}", mount_dir],
|
[
|
||||||
|
"-p", remote_port,
|
||||||
|
"#{remote_user}@#{remote_host}:#{remote_path}",
|
||||||
|
mount_dir
|
||||||
|
],
|
||||||
input: input,
|
input: input,
|
||||||
output: output,
|
output: output,
|
||||||
error: error
|
error: error
|
||||||
|
|
22
src/main.cr
22
src/main.cr
|
@ -6,11 +6,33 @@
|
||||||
require "yaml"
|
require "yaml"
|
||||||
require "colorize"
|
require "colorize"
|
||||||
require "json"
|
require "json"
|
||||||
|
require "log"
|
||||||
|
|
||||||
require "./filesystems/gocryptfs"
|
require "./filesystems/gocryptfs"
|
||||||
require "./config"
|
require "./config"
|
||||||
require "./cli"
|
require "./cli"
|
||||||
|
|
||||||
|
struct BaseFormat < Log::StaticFormatter
|
||||||
|
def run
|
||||||
|
string @entry.severity.label.downcase
|
||||||
|
string "("
|
||||||
|
source
|
||||||
|
string "): "
|
||||||
|
message
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Log.setup do |config|
|
||||||
|
backend = Log::IOBackend.new(formatter: BaseFormat)
|
||||||
|
config.bind "*", Log::Severity::Info, backend
|
||||||
|
|
||||||
|
if ENV["LOG_LEVEL"]?
|
||||||
|
level = Log::Severity.parse(ENV["LOG_LEVEL"]) || Log::Severity::Info
|
||||||
|
config.bind "*", level, backend
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
app = GX::Cli.new
|
app = GX::Cli.new
|
||||||
app.parse_command_line(ARGV)
|
app.parse_command_line(ARGV)
|
||||||
app.run
|
app.run
|
||||||
|
|
Loading…
Reference in a new issue