initial drop
This commit is contained in:
commit
a1c44e502d
17 changed files with 1133 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
__pycache__
|
||||
.idea
|
||||
output
|
||||
11
.gitlab-ci.yml
Normal file
11
.gitlab-ci.yml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
image: python:slim
|
||||
|
||||
before_script:
|
||||
- pip install -r requirements.txt
|
||||
|
||||
pages:
|
||||
script:
|
||||
- pelican content -s publishconf.py
|
||||
artifacts:
|
||||
paths:
|
||||
- output
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[submodule "flex"]
|
||||
path = flex
|
||||
url = https://github.com/alexandrevicenzi/Flex.git
|
||||
72
Makefile
Normal file
72
Makefile
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
PY?=python3
|
||||
PELICAN?=pelican
|
||||
PELICANOPTS=
|
||||
|
||||
BASEDIR=$(CURDIR)
|
||||
INPUTDIR=$(BASEDIR)/content
|
||||
OUTPUTDIR=$(BASEDIR)/output
|
||||
CONFFILE=$(BASEDIR)/pelicanconf.py
|
||||
PUBLISHCONF=$(BASEDIR)/publishconf.py
|
||||
|
||||
|
||||
DEBUG ?= 0
|
||||
ifeq ($(DEBUG), 1)
|
||||
PELICANOPTS += -D
|
||||
endif
|
||||
|
||||
RELATIVE ?= 0
|
||||
ifeq ($(RELATIVE), 1)
|
||||
PELICANOPTS += --relative-urls
|
||||
endif
|
||||
|
||||
SERVER ?= "0.0.0.0"
|
||||
|
||||
PORT ?= 0
|
||||
ifneq ($(PORT), 0)
|
||||
PELICANOPTS += -p $(PORT)
|
||||
endif
|
||||
|
||||
|
||||
help:
|
||||
@echo 'Makefile for a pelican Web site '
|
||||
@echo ' '
|
||||
@echo 'Usage: '
|
||||
@echo ' make html (re)generate the web site '
|
||||
@echo ' make clean remove the generated files '
|
||||
@echo ' make regenerate regenerate files upon modification '
|
||||
@echo ' make publish generate using production settings '
|
||||
@echo ' make serve [PORT=8000] serve site at http://localhost:8000'
|
||||
@echo ' make serve-global [SERVER=0.0.0.0] serve (as root) to $(SERVER):80 '
|
||||
@echo ' make devserver [PORT=8000] serve and regenerate together '
|
||||
@echo ' make devserver-global regenerate and serve on 0.0.0.0 '
|
||||
@echo ' '
|
||||
@echo 'Set the DEBUG variable to 1 to enable debugging, e.g. make DEBUG=1 html '
|
||||
@echo 'Set the RELATIVE variable to 1 to enable relative urls '
|
||||
@echo ' '
|
||||
|
||||
html:
|
||||
"$(PELICAN)" "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS)
|
||||
|
||||
clean:
|
||||
[ ! -d "$(OUTPUTDIR)" ] || rm -rf "$(OUTPUTDIR)"
|
||||
|
||||
regenerate:
|
||||
"$(PELICAN)" -r "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS)
|
||||
|
||||
serve:
|
||||
"$(PELICAN)" -l "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS)
|
||||
|
||||
serve-global:
|
||||
"$(PELICAN)" -l "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS) -b $(SERVER)
|
||||
|
||||
devserver:
|
||||
"$(PELICAN)" -lr "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(CONFFILE)" $(PELICANOPTS)
|
||||
|
||||
devserver-global:
|
||||
$(PELICAN) -lr $(INPUTDIR) -o $(OUTPUTDIR) -s $(CONFFILE) $(PELICANOPTS) -b 0.0.0.0
|
||||
|
||||
publish:
|
||||
"$(PELICAN)" "$(INPUTDIR)" -o "$(OUTPUTDIR)" -s "$(PUBLISHCONF)" $(PELICANOPTS)
|
||||
|
||||
|
||||
.PHONY: html help clean regenerate serve serve-global devserver publish
|
||||
BIN
content/images/avatar.png
Normal file
BIN
content/images/avatar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 104 KiB |
BIN
content/images/favicon.ico
Normal file
BIN
content/images/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
529
content/linux/archlinux_install_guide_2021.md
Normal file
529
content/linux/archlinux_install_guide_2021.md
Normal file
|
|
@ -0,0 +1,529 @@
|
|||
title: Arch Linux install guide 2022 Edition
|
||||
date: 2021-12-24
|
||||
tags: arch linux
|
||||
keywords: arch linux
|
||||
category: linux
|
||||
summary: This is how I setup Arch Linux in 2022
|
||||
|
||||
|
||||
# Introduction
|
||||
|
||||
This is the way I usually install Arch Linux. It is heavily based on systemd services to avoid the installation of additional software. Use it as inspiration for your own custom install.
|
||||
|
||||
Arch Linux is all about freedom of choice so these are the choices I made:
|
||||
|
||||
| Component | Implementation |
|
||||
| ---------------- | ----------------------------- |
|
||||
| Kernel | Default `linux` |
|
||||
| Partition layout | GPT |
|
||||
| Bootloader | `systemd-boot` |
|
||||
| Initramfs | `systemd` based `mkinitcpio` |
|
||||
| Partitioning | Primary partitions, single partition for root and home |
|
||||
| Encryption | LUKS2 for swap and rootfs |
|
||||
| Root filesystem | Ext4 |
|
||||
| Swap space | Dedicated partition |
|
||||
| Network manager | `systemd-networkd` |
|
||||
| Wifi | `wpa_supplicant` |
|
||||
| Mobile broadband | Custom `modem-manager` script |
|
||||
| Name resolution | `systemd-resolved` |
|
||||
| Network Time | `systemd-timesyncd` |
|
||||
| Text Editor | Neovim (`nvim`) |
|
||||
| User shell | `fish` |
|
||||
| `/bin/sh` Shell | `dash` |
|
||||
| Privilege excalation | `sudo` |
|
||||
| Desktop Environment | `xfce` |
|
||||
| Window Manager | `i3` |
|
||||
| Terminal | `xfce-terminal` |
|
||||
| Keyboard layout | en-us international with AtlGr dead keys; caps lock as compose key |
|
||||
|
||||
|
||||
Explanation for code examples:
|
||||
|
||||
```
|
||||
# command executed as root
|
||||
$ command executed as unprivileged user
|
||||
% command executed inside chroot as root
|
||||
```
|
||||
|
||||
## Assumptions
|
||||
|
||||
- You install to a notebook or desktop computer (ignore battery related things)
|
||||
- You install to an NVME drive
|
||||
- You read through my commands carefully and understand what they do before blindly pasting them into your machine
|
||||
- I'm not responsible for anything you do
|
||||
|
||||
|
||||
__With that out of the way, let's get started!__
|
||||
|
||||
# Installation
|
||||
|
||||
## Partition disks
|
||||
|
||||
Create 3 primary partitions for:
|
||||
|
||||
- ESP: 1GB, FAT32
|
||||
- Swap:
|
||||
- With hibernation support: same as RAM size
|
||||
- Without: ~2-8GB depending on the use case of the machine
|
||||
- RootFS: Rest of your disk
|
||||
|
||||
```
|
||||
# cfdisk -z /dev/nvme0n1
|
||||
# mkdosfs -F 32 -n ESP /dev/nvme0n1p1
|
||||
# cryptsetup LuksFormat --type luks2 --label CRYPTSWAP /dev/nvme0n1p2
|
||||
# cryptsetup LuksFormat --type luks2 --label CRYPTROOT /dev/nvme0n1p3
|
||||
# cryptsetup open --allow-discards --perf-no_read_workqueue --perf-no_write_workqueue --persistent --type luks2 /dev/nvme0n1p2 cryptswap
|
||||
# cryptsetup open --allow-discards --perf-no_read_workqueue --perf-no_write_workqueue --persistent --type luks2 /dev/nvme0n1p3 cryptroot
|
||||
# mkswap -L SWAP /dev/mapper/cryptswap
|
||||
# mkfs.ext4 -L ROOT -O metadata_csum /dev/mapper/cryptroot
|
||||
# mount /dev/mapper/cryptroot /mnt -o noatime,discard
|
||||
# mkdir /mnt/boot
|
||||
# mount /dev/nvme0n1p1 /mnt/boot -o noatime,discard
|
||||
# swapon -d /dev/mapper/cryptswap
|
||||
```
|
||||
|
||||
Final result should look like this:
|
||||
|
||||
```
|
||||
# lsblk
|
||||
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
|
||||
nvme0n1 259:0 0 953.9G 0 disk
|
||||
├─nvme0n1p1 259:1 0 1G 0 part /boot
|
||||
├─nvme0n1p2 259:2 0 32G 0 part
|
||||
│ └─cryptswap 254:1 0 32G 0 crypt [SWAP]
|
||||
└─nvme0n1p3 259:3 0 920.9G 0 part
|
||||
└─cryptroot 254:0 0 920.9G 0 crypt /
|
||||
```
|
||||
|
||||
|
||||
## Install base system
|
||||
|
||||
Some packages mentioned here depend on your hardware
|
||||
|
||||
```
|
||||
# pacstrap /mnt base base-devel linux linux-firmware (intel-ucode|amd-ucode) [sof-firmware] neovim man-db man-pages texinfo
|
||||
```
|
||||
|
||||
Generate fstab
|
||||
|
||||
```
|
||||
# genfstab -U /mnt >> /mnt/etc/fstab
|
||||
```
|
||||
|
||||
## Setup bootloader
|
||||
|
||||
Get UUIDs of drives:
|
||||
|
||||
```
|
||||
# blkid
|
||||
/dev/nvme0n1p1: LABEL_FATBOOT="ESP" LABEL="ESP" UUID="1234-0001" BLOCK_SIZE="512" TYPE="vfat" PARTUUID="deadbeef-1234-5678-90ab-10000001"
|
||||
/dev/nvme0n1p2: UUID="deadbeef-1234-5678-90ab-00000002" LABEL="CRYPTSWAP" TYPE="crypto_LUKS" PARTUUID="deadbeef-1234-5678-90ab-10000002"
|
||||
/dev/nvme0n1p3: UUID="deadbeef-1234-5678-90ab-00000003" LABEL="CRYPTROOT" TYPE="crypto_LUKS" PARTUUID="deadbeef-1234-5678-90ab-20000003"
|
||||
/dev/mapper/cryptswap: LABEL="SWAP" UUID="deadbeef-1234-5678-90ab-20000002" TYPE="swap"
|
||||
/dev/mapper/cryptroot: LABEL="ROOT" UUID="deadbeef-1234-5678-90ab-20000003" BLOCK_SIZE="4096" TYPE="ext4"
|
||||
```
|
||||
|
||||
Install and configure `systemd-boot`:
|
||||
|
||||
```
|
||||
# arch-chroot /mnt # we'll stay in chroot for a while so I'll not prefix every code block with that
|
||||
% bootctl install
|
||||
% nvim /boot/loader/loader.conf
|
||||
default arch.conf
|
||||
timeout 3
|
||||
console-mode keep
|
||||
editor yes
|
||||
auto-entries
|
||||
auto-firmware
|
||||
```
|
||||
|
||||
Setup boot entries:
|
||||
|
||||
```
|
||||
% nvim /boot/loader/entries/arch.conf
|
||||
title Arch Linux
|
||||
linux /vmlinuz-linux
|
||||
initrd /intel-ucode.img
|
||||
initrd /initramfs-linux.img
|
||||
options root="UUID=deadbeef-1234-5678-90ab-20000003" resume="UUID=deadbeef-1234-5678-90ab-20000002" rd.luks.name=deadbeef-1234-5678-90ab-00000003=cryptroot rd.luks.name=deadbeef-1234-5678-90ab-00000002=cryptswap rd.luks.options=discard rw
|
||||
|
||||
% nvim /boot/loader/entries/arch-fallback.conf
|
||||
title Arch Linux (fallback initramfs)
|
||||
linux /vmlinuz-linux
|
||||
initrd /intel-ucode.img
|
||||
initrd /initramfs-linux-fallback.img
|
||||
options root="UUID=deadbeef-1234-5678-90ab-20000003" resume="UUID=deadbeef-1234-5678-90ab-20000002" rd.luks.name=deadbeef-1234-5678-90ab-00000003=cryptroot rd.luks.name=deadbeef-1234-5678-90ab-00000002=cryptswap rd.luks.options=discard rw
|
||||
```
|
||||
|
||||
## Setup vconsole
|
||||
|
||||
```
|
||||
% nvim /etc/vconsole.conf
|
||||
KEYMAP=us
|
||||
FONT=lat2-16
|
||||
FONT_MAP=8859-2
|
||||
```
|
||||
|
||||
## Setup initramfs
|
||||
|
||||
Switching to `systemd` based initramfs:
|
||||
|
||||
```
|
||||
% nvim /etc/mkinitcpio.conf
|
||||
[...]
|
||||
HOOKS=(base systemd autodetect keyboard sd-vconsole modconf block sd-encrypt filesystems fsck)
|
||||
[...]
|
||||
|
||||
% mkinitcpio -P
|
||||
```
|
||||
|
||||
## Setup networking
|
||||
|
||||
Setup for wired connections:
|
||||
|
||||
```
|
||||
% nvim /etc/systemd/network/wired.network
|
||||
[Match]
|
||||
Name=enp*
|
||||
|
||||
[Network]
|
||||
DHCP=yes
|
||||
MulticastDNS=resolve
|
||||
DNSSEC=allow-downgrade
|
||||
|
||||
[DHCP]
|
||||
RouteMetric=10
|
||||
```
|
||||
|
||||
Setup for wireless connections:
|
||||
|
||||
```
|
||||
% nvim /etc/systemd/network/wireless.network
|
||||
[Match]
|
||||
Name=wlp*
|
||||
|
||||
[Network]
|
||||
DHCP=yes
|
||||
MulticastDNS=resolve
|
||||
DNSSEC=allow-downgrade
|
||||
IPv6PrivacyExtensions=kernel
|
||||
|
||||
[DHCP]
|
||||
RouteMetric=20
|
||||
```
|
||||
|
||||
Enable IPv6 privacy extensions:
|
||||
|
||||
Execute this first:
|
||||
|
||||
```
|
||||
% sysctl net.ipv6.conf.wlp3s0.addr_gen_mode=3
|
||||
% ip link set wlp3s0 down
|
||||
% ip link set wlp3s0 up
|
||||
% sysctl net.ipv6.conf.wlp3s0.stable_secret
|
||||
```
|
||||
|
||||
Take the secret from the last command and put it here:
|
||||
|
||||
```
|
||||
% nvim /etc/sysctl.d/40-ipv6.conf
|
||||
# Enable IPv6 Privacy Extensions
|
||||
net.ipv6.conf.all.use_tempaddr = 2
|
||||
net.ipv6.conf.default.use_tempaddr = 2
|
||||
net.ipv6.conf.wlp3s0.use_tempaddr = 2
|
||||
net.ipv6.conf.enp5s0.use_tempaddr = 2
|
||||
|
||||
# Enable IPv6 stable privacy mode
|
||||
net.ipv6.conf.wlp3s0.stable_secret = 25a3:36e6:9384:1111:9866:def1:abcd:1234
|
||||
net.ipv6.conf.wlp3s0.addr_gen_mode = 2
|
||||
```
|
||||
|
||||
Install additional packages for wifi and enable daemon on your wifi interface:
|
||||
|
||||
```
|
||||
$ yay -S wpa_supplicant
|
||||
# systemdctl enable wpa_supplicant@wlp3s0.service
|
||||
```
|
||||
|
||||
Setup for mobile broadband follows later.
|
||||
|
||||
```
|
||||
% systemctl enable systemd-networkd
|
||||
% systemctl enable systemd-resolved
|
||||
% rm /etc/resolv.conf
|
||||
% ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
|
||||
```
|
||||
|
||||
__The last command will break your DNS but that's fine because we will reboot in a moment.__
|
||||
__Maybe you have to do this after reboot. Definitly check if it worked.__
|
||||
|
||||
## Set hostname
|
||||
|
||||
```
|
||||
% echo "myhostname" > /etc/hostname
|
||||
```
|
||||
|
||||
## Setup network time and timezone
|
||||
|
||||
```
|
||||
% nvim /etc/systemd/timesyncd.conf
|
||||
[Time]
|
||||
NTP=0.arch.pool.ntp.org 1.arch.pool.ntp.org 2.arch.pool.ntp.org 3.arch.pool.ntp.org
|
||||
FallbackNTP=0.de.pool.ntp.org 1.de.pool.ntp.org 2.de.pool.ntp.org 3.de.pool.ntp.org
|
||||
|
||||
% systemctl enable systemd-timesyncd
|
||||
```
|
||||
|
||||
```
|
||||
% ln -sf /usr/share/zoneinfo/Europe/Berlin /etc/localtime
|
||||
% hwclock --systohc
|
||||
```
|
||||
|
||||
## Locale setup
|
||||
|
||||
Edit `/etc/locale.gen` file in your chroot and uncomment `en_US.UTF-8 UTF-8` locales. Then run:
|
||||
|
||||
```
|
||||
% locale-gen
|
||||
```
|
||||
|
||||
```
|
||||
% nvim /etc/locale.conf
|
||||
LANG=en_US.UTF-8
|
||||
LANGUAGE=en_US:en
|
||||
LC_COLLATE=C
|
||||
```
|
||||
|
||||
## Set root password
|
||||
|
||||
```
|
||||
% passwd
|
||||
```
|
||||
|
||||
## Reboot into new system
|
||||
|
||||
```
|
||||
% exit # exit chroot
|
||||
# umount -R /mnt
|
||||
# swapoff -a
|
||||
# cryptsetup close cryptroot
|
||||
# cryptsetup close cryptswap
|
||||
# reboot
|
||||
```
|
||||
|
||||
## Check if time is correct
|
||||
|
||||
```
|
||||
# timedatectl status
|
||||
Local time: Thu 2021-08-05 18:08:59 CEST
|
||||
Universal time: Thu 2021-08-05 16:08:59 UTC
|
||||
RTC time: Thu 2021-08-05 16:09:09
|
||||
Time zone: Europe/Berlin (CEST, +0200)
|
||||
System clock synchronized: no
|
||||
NTP service: inactive
|
||||
RTC in local TZ: no
|
||||
```
|
||||
|
||||
Enable synchronisation with:
|
||||
|
||||
```
|
||||
# timedatectl set-ntp true
|
||||
```
|
||||
|
||||
## Create unprivileged user
|
||||
|
||||
```
|
||||
# pacman -Syu sudo fish python pkgfile
|
||||
# useradd -m -G wheel -s /usr/bin/fish bob
|
||||
# EDITOR=nvim visudo
|
||||
[...]
|
||||
%wheel ALL=(ALL) ALL
|
||||
[...]
|
||||
|
||||
# passwd bob
|
||||
```
|
||||
|
||||
## Setup AUR
|
||||
|
||||
__Use unprivileged user from here on__
|
||||
|
||||
```
|
||||
$ sudo pacman -S git
|
||||
$ git clone https://aur.archlinux.org/yay.git
|
||||
$ cd yay
|
||||
$ makepkg -csi
|
||||
$ cd ..
|
||||
$ rm -fr yay
|
||||
```
|
||||
|
||||
## Some quality of live things
|
||||
|
||||
### Update systemd-boot on ESP when systemd is updated
|
||||
|
||||
```
|
||||
$ yay -S systemd-boot-pacman-hook
|
||||
```
|
||||
|
||||
### System monitoring with temperatures
|
||||
|
||||
```
|
||||
$ yay -S htop lsof strace lm_sensors
|
||||
# sensors-detect # hit enter until it stops
|
||||
```
|
||||
|
||||
### Use `dash` for `/bin/sh`
|
||||
|
||||
This could cause problems, use `checkbashisms` to check your scripts:
|
||||
|
||||
```
|
||||
$ yay -S checkbashisms
|
||||
$ find /usr/bin/ -type f -perm -o=r -print0 | xargs -0 gawk '/^#!.*( |[/])sh/{printf "%s\0", FILENAME} {nextfile}' | xargs -0 checkbashisms
|
||||
$ yay -S dashbinsh
|
||||
```
|
||||
|
||||
### Make pacman nice and fast
|
||||
|
||||
Edit `/etc/pacman.conf` and add/change these lines:
|
||||
|
||||
```
|
||||
Color
|
||||
VerbosePkgLists
|
||||
ParallelDownloads = 10
|
||||
ILoveCandy
|
||||
```
|
||||
|
||||
Also enable multilib:
|
||||
|
||||
```
|
||||
[multilib]
|
||||
Include = /etc/pacman.d/mirrorlist
|
||||
```
|
||||
|
||||
# Grafical setup
|
||||
|
||||
## Setup gdm
|
||||
|
||||
```
|
||||
$ yay -S gdm
|
||||
# systemctl enable gdm.service
|
||||
```
|
||||
|
||||
## Setup XFCE with i3 as window manager
|
||||
|
||||
Install packages first. Choose as many from these groups as you like. You can probably skip most panel plugins:
|
||||
|
||||
```
|
||||
$ yay -S xfce4 xfce4-goodies
|
||||
```
|
||||
|
||||
My favorites even under i3 are: `xfce4-screenshooter`, `xfce4-terminal`, `thunar`
|
||||
|
||||
For `thunar` setup `gvfs`:
|
||||
|
||||
```
|
||||
$ yay -S gvfs gvfs-afc gvfs-goa gvfs-google gvfs-gphoto2 gvfs-mtp gvfs-nfs gvfs-smb
|
||||
```
|
||||
|
||||
Install i3 (or i3-gaps if you wanna waste precious space just for looks):
|
||||
|
||||
```
|
||||
$ yay -S i3 i3blocks j4-dmenu-desktop
|
||||
```
|
||||
|
||||
Switch to i3 as window manager:
|
||||
|
||||
```
|
||||
xfconf-query -c xfce4-session -p /sessions/Failsafe/Client0_Command -t string -sa xfsettingsd
|
||||
xfconf-query -c xfce4-session -p /sessions/Failsafe/Client1_Command -t string -sa i3
|
||||
```
|
||||
|
||||
This should change the value from `xfwm4` to `i3` in `~/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-session.xml`.
|
||||
|
||||
## Fonts
|
||||
|
||||
```
|
||||
% yay -S ttf-droid ttf-dejavu \ # default stuff
|
||||
noto-fonts noto-fonts-cjk noto-fonts-emoji noto-fonts-extra \ # emoji
|
||||
adobe-source-code-pro-fonts \ # monospace
|
||||
adobe-source-sans-fonts \ # sans-serif
|
||||
adobe-source-han-sans-cn-fonts adobe-source-han-sans-tw-fonts adobe-source-han-serif-cn-fonts adobe-source-han-serif-tw-fonts \ # chinese
|
||||
adobe-source-han-sans-jp-fonts adobe-source-han-serif-jp-fonts \ # japanese
|
||||
adobe-source-han-sans-kr-fonts # korean
|
||||
```
|
||||
|
||||
# Bonus!
|
||||
|
||||
## Optimize pacman/yay
|
||||
|
||||
```
|
||||
$ yay -S ccache
|
||||
```
|
||||
|
||||
In `/etc/makepkg.conf`:
|
||||
|
||||
- For `CFLAGS` change `-march=native` and `-mtune=native`.
|
||||
- Set `MAKEFLAGS="-j8"` or any othe rnumber of cores you want to use
|
||||
- For `BUILDENV` enable `ccache`
|
||||
|
||||
## Wayland
|
||||
|
||||
Enable wayland support for Qt5/6
|
||||
|
||||
```
|
||||
$ yay -S qt5-wayland qt6-wayland glfw-wayland
|
||||
```
|
||||
|
||||
Enable wayland support for electron apps by editing `~/.config/electron-flags.conf`:
|
||||
|
||||
```
|
||||
--enable-features=UseOzonePlatform
|
||||
--ozone-platform=wayland
|
||||
```
|
||||
|
||||
Install XWayland to support X11 applications:
|
||||
|
||||
```
|
||||
$ yay -S xorg-xwayland
|
||||
```
|
||||
|
||||
## Sway
|
||||
|
||||
TBC
|
||||
|
||||
```
|
||||
yay -S sway \
|
||||
xdg-desktop-portal xdg-desktop-portal-wlr \ # screen sharing/webrtc
|
||||
```
|
||||
|
||||
## Gnome
|
||||
|
||||
Simply install the gnome group which includes most gnome packages you'll need:
|
||||
|
||||
```
|
||||
$ yay -S gnome gnome-tweaks webp-pixbuf-loader
|
||||
```
|
||||
|
||||
After a few hundred lines of things scroll by this the stuff that was too fast to read:
|
||||
|
||||
Install these packages that add features you propably want:
|
||||
|
||||
```
|
||||
$ yay -S qt5-svg \ # svg icon set support
|
||||
vulkan-mesa-layers \ # vulkan support
|
||||
vulkan-intel \ # vulkan support (intel)
|
||||
gst-libav gst-plugins-ugly \ # media file support
|
||||
intel-media-driver libva-intel-driver \ # media file support (intel)
|
||||
eog-plugins \ # image support for eye of gnome
|
||||
poppler-data \ # pdf feature support
|
||||
p7zip unrar \ # file-roller archive support
|
||||
gedit-plugins \
|
||||
fwupd dmidecode \ # firmware update support
|
||||
pipewire-alsa pipewire-pulse pipewire-zeroconf \ # pulseaudio replacement
|
||||
xdg-desktop-portal xdg-desktop-portal-gtk \ # screen sharing/webrtc
|
||||
gtk-engines \ # gtk2 themes
|
||||
chromium \ # browser
|
||||
evolution evolution-ews highlight \ # email client
|
||||
```
|
||||
|
||||
Enable pipewire support in chromium by enabling: `chrome://flags/#enable-webrtc-pipewire-capturer`
|
||||
|
||||
36
content/linux/pokeshell.md
Normal file
36
content/linux/pokeshell.md
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
title: Pokéshell
|
||||
date: 2016-01-01 23:30
|
||||
category: linux
|
||||
tags: pokemon, shell, bash, fish, imagemagick
|
||||
slug: pokeshell
|
||||
|
||||
A friend of me had the idea of a shell displaying a random pokémon on launch. I liked the idea and couldn't resist to implement it over christmas.
|
||||
|
||||
<!-- PELICAN_END_SUMMARY -->
|
||||
|
||||
What the package does is, it downloads all pokémon images in a defined range which is 1-151 by default (I'm old these are the ones I know) and converts the images to escape sequences. These are saved in `/usr/share/pokeshell`.
|
||||
|
||||
Now when you ipopen a new shell you could display one of them randomly by putting this code in your `~/.bashrc`:
|
||||
|
||||
```sh
|
||||
cat /usr/share/pokeshell/\$((\$RANDOM % 151 + 1)).pokemon
|
||||
```
|
||||
|
||||
Or if you use fish like me put this in your `~/.config/fish/functions/fish_prompt.fish`:
|
||||
|
||||
```sh
|
||||
function fish_greeting
|
||||
set r (random)
|
||||
cat /usr/share/pokeshell/(math \"\$r % 151 + 1\").pokemon
|
||||
end
|
||||
```
|
||||
|
||||
The images are downloaded using the [Pokéapi][pokeapi]. For the conversation I use Imagemagick and a tool called [img2xterm][img2xterm].
|
||||
|
||||
You can find the package in the [AUR][aur-pokeshell].
|
||||
|
||||
|
||||
[pokeapi]: http://pokeapi.co
|
||||
[img2xterm]: https://github.com/rossy/img2xterm
|
||||
[aur-pokeshell]: https://aur.archlinux.org/packages/pokeshell/
|
||||
|
||||
1
flex
Submodule
1
flex
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 7e99f9bbe681a5b7edef9748bc6f6ae10f4862a7
|
||||
140
pelicanconf.py
Normal file
140
pelicanconf.py
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
from datetime import datetime
|
||||
|
||||
AUTHOR = 'XenGi'
|
||||
SITEURL = ''
|
||||
SITENAME = 'XenGis blog'
|
||||
SITETITLE = 'XenGi'
|
||||
SITESUBTITLE = ''
|
||||
SITEDESCRIPTION = 'A typical way to world domination'
|
||||
SITELOGO = SITEURL + '/images/avatar.png'
|
||||
FAVICON = SITEURL + '/images/favicon.ico'
|
||||
BROWSER_COLOR = '#333'
|
||||
ROBOTS = 'index, follow'
|
||||
CC_LICENSE = {
|
||||
'name': 'Creative Commons Attribution-ShareAlike',
|
||||
'version': '4.0',
|
||||
'slug': 'by-sa',
|
||||
'icon': True,
|
||||
'language': 'en_US',
|
||||
}
|
||||
COPYRIGHT_NAME = AUTHOR
|
||||
COPYRIGHT_YEAR = datetime.now().year
|
||||
STATIC_PATHS = [
|
||||
'extra/custom.css'
|
||||
]
|
||||
EXTRA_PATH_METADATA = {
|
||||
'extra/custom.css': {'path': 'static/custom.css'},
|
||||
}
|
||||
CUSTOM_CSS = 'static/custom.css'
|
||||
MAIN_MENU = True
|
||||
PLUGINS = [
|
||||
'post_stats',
|
||||
]
|
||||
PLUGIN_PATHS = [
|
||||
'plugins/'
|
||||
]
|
||||
JINJA_ENVIRONMENT = {}
|
||||
I18N_TEMPLATES_LANG = 'en'
|
||||
DEFAULT_LANG = 'en'
|
||||
OG_LOCALE = 'en_US'
|
||||
LOCALE = 'en_US'
|
||||
THEME = 'flex'
|
||||
OUTPUT_PATH = 'output/'
|
||||
PATH = 'content/'
|
||||
TIMEZONE = 'Europe/Berlin'
|
||||
# Feed generation is usually not desired when developing
|
||||
FEED_ALL_ATOM = None
|
||||
CATEGORY_FEED_ATOM = None
|
||||
TRANSLATION_FEED_ATOM = None
|
||||
AUTHOR_FEED_ATOM = None
|
||||
AUTHOR_FEED_RSS = None
|
||||
USE_FOLDER_AS_CATEGORY = False
|
||||
# Social widget
|
||||
MENUITEMS = []
|
||||
SOCIAL = [
|
||||
('Email', 'mailto:blog@xengi.de'),
|
||||
]
|
||||
MENUITEMS = [
|
||||
('Archives', '/archives.html'),
|
||||
('Categories', '/categories.html'),
|
||||
('Tags', '/tags.html'),
|
||||
]
|
||||
STATIC_PATHS = [
|
||||
'images',
|
||||
]
|
||||
DEFAULT_PAGINATION = False
|
||||
USE_GOOGLE_FONTS = True
|
||||
|
||||
# Uncomment following line if you want document-relative URLs when developing
|
||||
#RELATIVE_URLS = True
|
||||
|
||||
DEFAULT_CATEGORY = 'misc'
|
||||
DISPLAY_PAGES_ON_MENU = True
|
||||
DISPLAY_CATEGORIES_ON_MENU = True
|
||||
MARKDOWN = {
|
||||
'extension_configs': {
|
||||
'markdown.extensions.codehilite': {'css_class': 'highlight'},
|
||||
'markdown.extensions.extra': {},
|
||||
'markdown.extensions.meta': {},
|
||||
'markdown.extensions.nl2br': {},
|
||||
'markdown.extensions.smarty': {},
|
||||
'markdown.extensions.sane_lists': {},
|
||||
},
|
||||
'output_format': 'xhtml5',
|
||||
}
|
||||
PAGE_PATHS = ['pages']
|
||||
STATIC_PATHS = ['images']
|
||||
TYPOGRIFY = True
|
||||
ARTICLE_URL = 'posts/{date:%Y}/{date:%b}/{date:%d}/{slug}/'
|
||||
ARTICLE_SAVE_AS = 'posts/{date:%Y}/{date:%b}/{date:%d}/{slug}/index.html'
|
||||
PAGE_URL = 'pages/{slug}/'
|
||||
PAGE_SAVE_AS = 'pages/{slug}/index.html'
|
||||
AUTHOR_URL = 'author/{slug}.html'
|
||||
AUTHOR_SAVE_AS = 'author/{slug}.html'
|
||||
CATEGORY_URL = 'category/{slug}.html'
|
||||
CATEGORY_SAVE_AS = 'category/{slug}.html'
|
||||
TAG_URL = 'tag/{slug}.html'
|
||||
TAG_SAVE_AS = 'tag/{slug}.html'
|
||||
|
||||
# Flex settings
|
||||
|
||||
USE_LESS = True
|
||||
|
||||
## dark mode
|
||||
|
||||
THEME_COLOR = 'dark'
|
||||
THEME_COLOR_AUTO_DETECT_BROWSER_PREFERENCE = True
|
||||
THEME_COLOR_ENABLE_USER_OVERRIDE = True
|
||||
|
||||
## code highlight
|
||||
|
||||
PYGMENTS_STYLE = 'emacs'
|
||||
PYGMENTS_STYLE_DARK = 'monokai'
|
||||
#PYGMENTS_STYLE = 'solarized-light'
|
||||
#PYGMENTS_STYLE_DARK = 'solarized-dark'
|
||||
|
||||
# Plugin settings
|
||||
|
||||
## related posts
|
||||
|
||||
RELATED_POSTS_MAX = 10
|
||||
|
||||
## sitemap
|
||||
|
||||
SITEMAP = {
|
||||
'format': 'xml',
|
||||
'priorities': {
|
||||
'articles': 0.5,
|
||||
'indexes': 0.5,
|
||||
'pages': 0.5
|
||||
},
|
||||
'changefreqs': {
|
||||
'articles': 'monthly',
|
||||
'indexes': 'daily',
|
||||
'pages': 'monthly'
|
||||
}
|
||||
}
|
||||
|
||||
## isso
|
||||
|
||||
ISSO_URL = ''
|
||||
1
plugins/post_stats/__init__.py
Normal file
1
plugins/post_stats/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
from .post_stats import *
|
||||
71
plugins/post_stats/post_stats.py
Normal file
71
plugins/post_stats/post_stats.py
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Post Statistics
|
||||
========================
|
||||
|
||||
This plugin calculates various statistics about a post and stores them in an article.stats dictionary:
|
||||
|
||||
wc: how many words
|
||||
read_mins: how many minutes to read this article, based on 250 wpm (http://en.wikipedia.org/wiki/Words_per_minute#Reading_and_comprehension)
|
||||
word_counts: frquency count of all the words in the article; can be used for tag/word clouds/
|
||||
fi: Flesch-kincaid Index/ Reading Ease
|
||||
fk: Flesch-kincaid Grade Level
|
||||
|
||||
"""
|
||||
|
||||
from pelican import signals
|
||||
from bs4 import BeautifulSoup
|
||||
import re
|
||||
from collections import Counter
|
||||
|
||||
from .readability import *
|
||||
|
||||
|
||||
def calculate_stats(instance):
|
||||
|
||||
if instance._content is not None:
|
||||
stats = {}
|
||||
content = instance._content
|
||||
|
||||
# How fast do average people read?
|
||||
WPM = 250
|
||||
|
||||
# Use BeautifulSoup to get readable/visible text
|
||||
raw_text = BeautifulSoup(content, 'html.parser').getText()
|
||||
|
||||
# Process the text to remove entities
|
||||
entities = r'\&\#?.+?;'
|
||||
raw_text = raw_text.replace(' ', ' ')
|
||||
raw_text = re.sub(entities, '', raw_text)
|
||||
|
||||
# Flesch-kincaid readbility stats counts sentances,
|
||||
# so save before removing punctuation
|
||||
tmp = raw_text
|
||||
|
||||
# Process the text to remove punctuation
|
||||
drop = u'.,?!@#$%^&*()_+-=\|/[]{}`~:;\'\"‘’—…“”'
|
||||
raw_text = raw_text.translate(dict((ord(c), u'') for c in drop))
|
||||
|
||||
# Count the words in the text
|
||||
words = raw_text.lower().split()
|
||||
word_count = Counter(words)
|
||||
|
||||
# Return the stats
|
||||
stats['word_counts'] = word_count
|
||||
stats['wc'] = sum(word_count.values())
|
||||
|
||||
# Calulate how long it'll take to read, rounding up
|
||||
stats['read_mins'] = (stats['wc'] + WPM - 1) // WPM
|
||||
if stats['read_mins'] == 0:
|
||||
stats['read_mins'] = 1
|
||||
|
||||
# Calculate Flesch-kincaid readbility stats
|
||||
readability_stats = stcs, words, sbls = text_stats(tmp, stats['wc'])
|
||||
stats['fi'] = "{:.2f}".format(flesch_index(readability_stats))
|
||||
stats['fk'] = "{:.2f}".format(flesch_kincaid_level(readability_stats))
|
||||
|
||||
instance.stats = stats
|
||||
|
||||
|
||||
def register():
|
||||
signals.content_object_init.connect(calculate_stats)
|
||||
56
plugins/post_stats/readability.py
Normal file
56
plugins/post_stats/readability.py
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Adadpted from here: http://acdx.net/calculating-the-flesch-kincaid-level-in-python/
|
||||
# See here for details: http://en.wikipedia.org/wiki/Flesch%E2%80%93Kincaid_readability_test
|
||||
|
||||
from __future__ import division
|
||||
import re
|
||||
|
||||
|
||||
def mean(seq):
|
||||
return sum(seq) / len(seq)
|
||||
|
||||
|
||||
def syllables(word):
|
||||
if len(word) <= 3:
|
||||
return 1
|
||||
|
||||
word = re.sub(r"(es|ed|(?<!l)e)$", "", word)
|
||||
return len(re.findall(r"[aeiouy]+", word))
|
||||
|
||||
|
||||
def normalize(text):
|
||||
terminators = ".!?:;"
|
||||
term = re.escape(terminators)
|
||||
text = re.sub(r"[^%s\sA-Za-z]+" % term, "", text)
|
||||
text = re.sub(r"\s*([%s]+\s*)+" % term, ". ", text)
|
||||
return re.sub(r"\s+", " ", text)
|
||||
|
||||
|
||||
def text_stats(text, wc):
|
||||
text = normalize(text)
|
||||
stcs = [s.split(" ") for s in text.split(". ")]
|
||||
stcs = [s for s in stcs if len(s) >= 2]
|
||||
|
||||
if wc:
|
||||
words = wc
|
||||
else:
|
||||
words = sum(len(s) for s in stcs)
|
||||
|
||||
sbls = sum(syllables(w) for s in stcs for w in s)
|
||||
|
||||
return len(stcs), words, sbls
|
||||
|
||||
|
||||
def flesch_index(stats):
|
||||
stcs, words, sbls = stats
|
||||
if stcs == 0 or words == 0:
|
||||
return 0
|
||||
return 206.835 - 1.015 * (words / stcs) - 84.6 * (sbls / words)
|
||||
|
||||
|
||||
def flesch_kincaid_level(stats):
|
||||
stcs, words, sbls = stats
|
||||
if stcs == 0 or words == 0:
|
||||
return 0
|
||||
return 0.39 * (words / stcs) + 11.8 * (sbls / words) - 15.59
|
||||
49
plugins/post_stats/readme.rst
Normal file
49
plugins/post_stats/readme.rst
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
Post Statistics
|
||||
==================
|
||||
|
||||
A Pelican plugin to calculate various statistics about a post and store them in an article.stats dictionary:
|
||||
|
||||
- ``wc``: how many words
|
||||
- ``read_mins``: how many minutes would it take to read this article, based on 250 wpm (http://en.wikipedia.org/wiki/Words_per_minute#Reading_and_comprehension)
|
||||
- ``word_counts``: frquency count of all the words in the article; can be used for tag/word clouds
|
||||
- ``fi``: Flesch-kincaid Index/ Reading Ease (see: http://en.wikipedia.org/wiki/Flesch%E2%80%93Kincaid_readability_tests)
|
||||
- ``fk``: Flesch-kincaid Grade Level
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
{
|
||||
'wc': 2760,
|
||||
'fi': '65.94',
|
||||
'fk': '7.65',
|
||||
'word_counts': Counter({u'to': 98, u'a': 90, u'the': 83, u'of': 50, ...}),
|
||||
'read_mins': 12
|
||||
}
|
||||
|
||||
This allows you to output these values in your templates, like this, for example:
|
||||
|
||||
.. code-block:: html+jinja
|
||||
|
||||
<p title="~{{ article.stats['wc'] }} words">~{{ article.stats['read_mins'] }} min read</p>
|
||||
<ul>
|
||||
<li>Flesch-kincaid Index/ Reading Ease: {{ article.stats['fi'] }}</li>
|
||||
<li>Flesch-kincaid Grade Level: {{ article.stats['fk'] }}</li>
|
||||
</ul>
|
||||
|
||||
The ``word_counts`` variable is a python ``Counter`` dictionary and looks something like this, with each unique word and it's frequency:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
Counter({u'to': 98, u'a': 90, u'the': 83, u'of': 50, u'karma': 50, .....
|
||||
|
||||
and can be used to create a tag/word cloud for a post.
|
||||
|
||||
Requirements
|
||||
----------------
|
||||
|
||||
`post_stats` requires BeautifulSoup.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ pip install beautifulsoup4
|
||||
28
publishconf.py
Normal file
28
publishconf.py
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# This file is only used if you use `make publish` or
|
||||
# explicitly specify it as your config file.
|
||||
|
||||
import os
|
||||
import sys
|
||||
sys.path.append(os.curdir)
|
||||
from pelicanconf import *
|
||||
|
||||
# If your site is available via HTTPS, make sure SITEURL begins with https://
|
||||
SITEURL = 'https://xengi.de'
|
||||
RELATIVE_URLS = False
|
||||
|
||||
FEED_ATOM = 'feeds/atom.xml'
|
||||
FEED_RSS = 'feeds/rss.xml'
|
||||
FEED_ALL_ATOM = 'feeds/all.atom.xml'
|
||||
FEED_ALL_RSS = 'feeds/all.rss.xml'
|
||||
CATEGORY_FEED_ATOM = 'feeds/category/%s.atom.xml'
|
||||
CATEGORY_FEED_RSS = 'feeds/category/%s.rss.xml'
|
||||
AUTHOR_FEED_ATOM = 'feeds/author/%s.atom.xml'
|
||||
AUTHOR_FEED_RSS = 'feeds/author/%s.rss.xml'
|
||||
TAG_FEED_ATOM = 'feeds/tag/%s.atom.xml'
|
||||
TAG_FEED_RSS = 'feeds/tag/%s.rss.xml'
|
||||
|
||||
DELETE_OUTPUT_DIRECTORY = True
|
||||
|
||||
USE_LESS = False
|
||||
7
requirements.txt
Normal file
7
requirements.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
pelican[markdown]
|
||||
markdown
|
||||
pelican-sitemap
|
||||
pelican-related-posts
|
||||
pelican-neighbors
|
||||
typogrify
|
||||
beautifulsoup4 # plugin: post_stats, summary
|
||||
126
tasks.py
Normal file
126
tasks.py
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import shlex
|
||||
import shutil
|
||||
import sys
|
||||
import datetime
|
||||
|
||||
from invoke import task
|
||||
from invoke.main import program
|
||||
from invoke.util import cd
|
||||
from pelican import main as pelican_main
|
||||
from pelican.server import ComplexHTTPRequestHandler, RootedHTTPServer
|
||||
from pelican.settings import DEFAULT_CONFIG, get_settings_from_file
|
||||
|
||||
SETTINGS_FILE_BASE = 'pelicanconf.py'
|
||||
SETTINGS = {}
|
||||
SETTINGS.update(DEFAULT_CONFIG)
|
||||
LOCAL_SETTINGS = get_settings_from_file(SETTINGS_FILE_BASE)
|
||||
SETTINGS.update(LOCAL_SETTINGS)
|
||||
|
||||
CONFIG = {
|
||||
'settings_base': SETTINGS_FILE_BASE,
|
||||
'settings_publish': 'publishconf.py',
|
||||
# Output path. Can be absolute or relative to tasks.py. Default: 'output'
|
||||
'deploy_path': SETTINGS['OUTPUT_PATH'],
|
||||
# Host and port for `serve`
|
||||
'host': 'localhost',
|
||||
'port': 8000,
|
||||
}
|
||||
|
||||
@task
|
||||
def clean(c):
|
||||
"""Remove generated files"""
|
||||
if os.path.isdir(CONFIG['deploy_path']):
|
||||
shutil.rmtree(CONFIG['deploy_path'])
|
||||
os.makedirs(CONFIG['deploy_path'])
|
||||
|
||||
@task
|
||||
def build(c):
|
||||
"""Build local version of site"""
|
||||
pelican_run('-s {settings_base}'.format(**CONFIG))
|
||||
|
||||
@task
|
||||
def rebuild(c):
|
||||
"""`build` with the delete switch"""
|
||||
pelican_run('-d -s {settings_base}'.format(**CONFIG))
|
||||
|
||||
@task
|
||||
def regenerate(c):
|
||||
"""Automatically regenerate site upon file modification"""
|
||||
pelican_run('-r -s {settings_base}'.format(**CONFIG))
|
||||
|
||||
@task
|
||||
def serve(c):
|
||||
"""Serve site at http://$HOST:$PORT/ (default is localhost:8000)"""
|
||||
|
||||
class AddressReuseTCPServer(RootedHTTPServer):
|
||||
allow_reuse_address = True
|
||||
|
||||
server = AddressReuseTCPServer(
|
||||
CONFIG['deploy_path'],
|
||||
(CONFIG['host'], CONFIG['port']),
|
||||
ComplexHTTPRequestHandler)
|
||||
|
||||
sys.stderr.write('Serving at {host}:{port} ...\n'.format(**CONFIG))
|
||||
server.serve_forever()
|
||||
|
||||
@task
|
||||
def reserve(c):
|
||||
"""`build`, then `serve`"""
|
||||
build(c)
|
||||
serve(c)
|
||||
|
||||
@task
|
||||
def preview(c):
|
||||
"""Build production version of site"""
|
||||
pelican_run('-s {settings_publish}'.format(**CONFIG))
|
||||
|
||||
@task
|
||||
def livereload(c):
|
||||
"""Automatically reload browser tab upon file modification."""
|
||||
from livereload import Server
|
||||
|
||||
def cached_build():
|
||||
cmd = '-s {settings_base} -e CACHE_CONTENT=True LOAD_CONTENT_CACHE=True'
|
||||
pelican_run(cmd.format(**CONFIG))
|
||||
|
||||
cached_build()
|
||||
server = Server()
|
||||
theme_path = SETTINGS['THEME']
|
||||
watched_globs = [
|
||||
CONFIG['settings_base'],
|
||||
'{}/templates/**/*.html'.format(theme_path),
|
||||
]
|
||||
|
||||
content_file_extensions = ['.md', '.rst']
|
||||
for extension in content_file_extensions:
|
||||
content_glob = '{0}/**/*{1}'.format(SETTINGS['PATH'], extension)
|
||||
watched_globs.append(content_glob)
|
||||
|
||||
static_file_extensions = ['.css', '.js']
|
||||
for extension in static_file_extensions:
|
||||
static_file_glob = '{0}/static/**/*{1}'.format(theme_path, extension)
|
||||
watched_globs.append(static_file_glob)
|
||||
|
||||
for glob in watched_globs:
|
||||
server.watch(glob, cached_build)
|
||||
server.serve(host=CONFIG['host'], port=CONFIG['port'], root=CONFIG['deploy_path'])
|
||||
|
||||
|
||||
@task
|
||||
def publish(c):
|
||||
"""Publish to production via rsync"""
|
||||
pelican_run('-s {settings_publish}'.format(**CONFIG))
|
||||
c.run(
|
||||
'rsync --delete --exclude ".DS_Store" -pthrvz -c '
|
||||
'-e "ssh -p {ssh_port}" '
|
||||
'{} {ssh_user}@{ssh_host}:{ssh_path}'.format(
|
||||
CONFIG['deploy_path'].rstrip('/') + '/',
|
||||
**CONFIG))
|
||||
|
||||
|
||||
def pelican_run(cmd):
|
||||
cmd += ' ' + program.core.remainder # allows to pass-through args to pelican
|
||||
pelican_main(shlex.split(cmd))
|
||||
Loading…
Reference in a new issue