Slide 1

Slide 1 text

Working without Workspace Oliver Davies (@opdavies)

Slide 2

Slide 2 text

Working with Workspace @opdavies

Slide 3

Slide 3 text

Operating system Personal: • Linux • NixOS • KDE Plasma Work: • Windows 10 • WSL (Ubuntu) • Nix package manager @opdavies

Slide 4

Slide 4 text

Nix and NixOS • Declarative • Reproducable • Nix Packages collection (nixpkgs) has over 80,000 packages • Easy to add to and edit, and contribute to @opdavies

Slide 5

Slide 5 text

nix-env -iA php82 @opdavies

Slide 6

Slide 6 text

nix-shell --packages php82 @opdavies

Slide 7

Slide 7 text

nix-shell --packages php82 --command "php -v" @opdavies

Slide 8

Slide 8 text

configuration.nix 1 { config, pkgs, ... }: 2 { 3 imports = [ ./hardware-configuration.nix ]; 4 5 nix.settings.experimental-features = [ "nix-command" "flakes" ]; 6 7 boot.loader.systemd-boot.enable = true; 8 boot.loader.efi.canTouchEfiVariables = true; 9 boot.loader.efi.efiSysMountPoint = "/boot/efi"; 10 11 boot.kernelPackages = pkgs.linuxPackages_latest; 12 13 networking.hostName = "nixedo"; 14 @opdavies

Slide 9

Slide 9 text

15 networking.networkmanager.enable = true; 16 17 time.timeZone = "Europe/London"; 18 19 i18n.defaultLocale = "en_GB.UTF-8"; 20 21 users.users.opdavies = { 22 isNormalUser = true; 23 description = "Oliver Davies"; 24 extraGroups = [ "docker" "networkmanager" "wheel" ]; 25 packages = with pkgs; [ firefox ]; 26 }; @opdavies

Slide 10

Slide 10 text

hardware-configuration.nix 1 { config, lib, pkgs, modulesPath, ... }: 2 3 { 4 imports = [ (modulesPath + "/installer/scan/not-detected.nix") ]; 5 6 boot.initrd.availableKernelModules = 7 [ "xhci_pci" "thunderbolt" "nvme" "usb_storage" "sd_mod" ]; 8 boot.initrd.kernelModules = [ ]; 9 boot.kernelModules = [ "kvm-intel" ]; 10 boot.kernelParams = [ "i8042.reset" ]; 11 boot.extraModulePackages = [ ]; 12 13 14 fileSystems."/" = { @opdavies

Slide 11

Slide 11 text

15 device = "/dev/disk/by-uuid/7c6d69ec-ba06-4ddb-b9c4-62b3994fda91"; 16 fsType = "ext4"; 17 }; 18 19 fileSystems."/boot/efi" = { 20 device = "/dev/disk/by-uuid/B729-9A75"; 21 fsType = "vfat"; 22 }; 23 24 swapDevices = 25 [{ device = "/dev/disk/by-uuid/5db0a0e6-93fb-4d0b-8fb0-fdb3cb76b89d"; }]; @opdavies

Slide 12

Slide 12 text

sudo nixos-rebuild build --flake .#nixedo @opdavies

Slide 13

Slide 13 text

dotfiles • System configuration files • Usually hidden, filenames start with a dot (.zshrc, .gitconfig, .config/) • Maintained on GitHub since July 2015 • https://opdavi.es/dotfiles • Managed with Home Manager @opdavies

Slide 14

Slide 14 text

home-manager/home.nix 1 { config, pkgs, ... }: 2 3 { 4 home.username = "opdavies"; 5 home.homeDirectory = "/home/opdavies"; 6 7 home.packages = with pkgs; [ 8 php82 9 php82Packages.composer 10 ]; 11 }; @opdavies

Slide 15

Slide 15 text

home-manager build -f home-manager/home.nix --flake .#wsl2 @opdavies

Slide 16

Slide 16 text

Z Shell @opdavies

Slide 17

Slide 17 text

Why zsh? • Replacement for the bash shell • Default on macOS • Separate to "oh-my-zsh" • OMZSH plugins and themes can be installed using zplug • Aliases • Globbing and expanding @opdavies

Slide 18

Slide 18 text

Aliases 1 alias cp="cp -v" 2 alias mv="mv -v" 3 alias rm="rm -v" 4 5 alias g="git" 6 alias gs="git status" 7 8 alias dk="docker" 9 alias dkp="docker ps" 10 alias dkc="docker compose" 11 alias dkcu="docker compose up" 12 13 alias docker-composer="docker-compose" @opdavies

Slide 19

Slide 19 text

Globbing and expanding Changing a file prefix: mv index.{html,twig} mv index.html index.twig Creating two files with different prefixes: touch my-component.{config.yml,twig} Creating a range of files: touch {1..10}.php @opdavies

Slide 20

Slide 20 text

Auto-expanding 1 expand-alias-space() { 2 [[ $LBUFFER =~ "\<(''${(j:|:)baliases})\$" ]]; insertBlank=$? 3 if [[ ! $LBUFFER =~ "\<(''${(j:|:)ialiases})\$" ]]; then 4 zle _expand_alias 5 fi 6 7 zle self-insert 8 9 if [[ "$insertBlank" = "0" ]]; then 10 zle backward-delete-char 11 fi 12 } 13 14 zle -N expand-alias-space @opdavies

Slide 21

Slide 21 text

15 16 bindkey " " expand-alias-space @opdavies

Slide 22

Slide 22 text

Git Customised to my preferences, managed by Home Manager: 1 programs.git = { 2 enable = true; 3 userName = "Oliver Davies"; 4 userEmail = "oliver@oliverdavies.uk"; 5 6 aliases = { 7 aa = "add --all"; 8 assume = "update-index --assume-unchanged"; 9 assumed = "!git ls-files -v | grep '^[hsmrck?]' | cut -c 3-"; 10 b = "branch"; 11 # ... 12 }; 13 extraConfig = { @opdavies

Slide 23

Slide 23 text

14 branch = { 15 autosetupmerge = true; 16 autosetuprebase = "always"; 17 }; 18 checkout.defaultRemote = "origin"; 19 color.ui = true; 20 commit = { 21 template = "~/.gitmessage"; 22 }; 23 core = { 24 editor = "nvim"; 25 excludesFile = "~/.gitignore-global"; 26 pager = "delta"; 27 }; @opdavies

Slide 24

Slide 24 text

[alias] aa = "add --all" assume = "update-index --assume-unchanged" assumed = "!git ls-files -v | grep '^[hsmrck?]' | cut -c 3-" b = "branch" browse = "!gh repo view --web" ca = "commit --amend --verbose" car = "commit --amend --no-edit" [branch] autosetupmerge = true autosetuprebase = "always" [checkout] defaultRemote = "origin" @opdavies

Slide 25

Slide 25 text

just @opdavies

Slide 26

Slide 26 text

justfile default: @just --list _exec +args: docker compose exec {{ args }} # Run Composer composer *args: just _exec php composer {{ args }} # Run Drush commands drush *args: just _exec php drush {{ args }} @opdavies

Slide 27

Slide 27 text

# Install Drupal install *args: just drush site:install -y {{ args }} # Run Artisan commands (Laravel) artisan *args: docker compose run \ --entrypoint php \ --rm \ --tty \ php artisan {{ args }} @opdavies

Slide 28

Slide 28 text

just composer require drupal/override_node_options @opdavies

Slide 29

Slide 29 text

just drush cache-rebuild just install localgov @opdavies

Slide 30

Slide 30 text

Generating configuration files @opdavies

Slide 31

Slide 31 text

build-configs Most of my projects have the same configuration files: • Dockerfile • docker-compose.yaml • justfile • phpstan.neon.dist • phpunit.xml.dist @opdavies

Slide 32

Slide 32 text

build-configs • Symfony/Silly CLI project • Twig for templating • Takes values from a build.yaml file • Generates the appropriate files with the correct configuration • Easier to set up a new project • Less maintenance overhead • Can quickly add a new feature and update every project @opdavies

Slide 33

Slide 33 text

build.yaml 1 name: docker-example-drupal 2 language: php 3 type: drupal-project 4 5 web: 6 type: nginx 7 8 database: 9 type: mariadb 10 version: 10 11 12 php: 13 version: 8.1-fpm-bullseye 14 phpcs: @opdavies

Slide 34

Slide 34 text

15 standard: Drupal,DrupalPractice 16 phpstan: 17 level: max 18 19 drupal: 20 docroot: web 21 22 docker-compose: 23 services: 24 database: ~ 25 php: 26 build: 27 target: build 28 29 dockerfile: 30 stages: 31 build: @opdavies

Slide 35

Slide 35 text

32 extends: base 33 packages: 34 - git 35 - libpng-dev 36 - libzip-dev 37 - mariadb-client 38 - unzip 39 extensions: 40 install: 41 - gd 42 - pdo_mysql 43 - zip 44 commands: 45 - composer validate --strict 46 - composer install @opdavies

Slide 36

Slide 36 text

Dockerfile.twig 1 FROM php:{{ php.version }} AS base 2 3 COPY --from=composer:2 /usr/bin/composer /usr/bin/composer 4 RUN which composer && composer -V 5 6 ARG DOCKER_UID=1000 7 ENV DOCKER_UID="${DOCKER_UID}" 8 9 WORKDIR {{ project_root }} 10 11 RUN adduser --disabled-password --uid "${DOCKER_UID}" app \ 12 && chown app:app -R {{ project_root }} @opdavies

Slide 37

Slide 37 text

docker-compose.yaml.twig 1 {% if "php" == language %} 2 php: 3 <<: *default-app 4 build: 5 context: . 6 target: build 7 args: 8 - "DOCKER_UID=${DOCKER_UID:-1000}" 9 volumes: 10 - .:{{ project_root }} 11 {% if "database" in dockerCompose.services|keys -%} 12 depends_on: 13 - database @opdavies

Slide 38

Slide 38 text

14 {% endif -%} 15 profiles: [php] @opdavies

Slide 39

Slide 39 text

justfile.twig 1 {% if "php" is same as language %} 2 composer *args: 3 {{ "just _exec php composer {{ args }}" | raw }} 4 5 {% if "drupal-project" is same as type %} 6 drush *args: 7 {{ "just _exec php drush {{ args }}" | raw }} 8 9 install *args: 10 {{ "just _exec php drush site:install -y {{ args }}" | raw }} 11 {% endif %} 12 {% endif %} @opdavies

Slide 40

Slide 40 text

Nix Flakes • Per project • Uses nixpkgs to create a development shell • Can create build artifacts (phar?) • Could replace Docker and Docker Compose @opdavies

Slide 41

Slide 41 text

flake.nix 1 { 2 inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; 3 inputs.devshell.url = "github:numtide/devshell"; 4 5 outputs = inputs@{ flake-parts, ... }: 6 flake-parts.lib.mkFlake { inherit inputs; } { 7 imports = [ inputs.devshell.flakeModule ]; 8 9 systems = [ "x86_64-linux" ]; 10 11 perSystem = { config, self', inputs', pkgs, system, ... }: { 12 devshells.default = { 13 packages = with pkgs; [ php82 php82Packages.composer ]; 14 }; @opdavies

Slide 42

Slide 42 text

15 }; 16 17 flake = { }; 18 }; 19 } @opdavies

Slide 43

Slide 43 text

neovim • Community-maintained fork of Vim • Configured with Lua • nvim-lspconfig for language server support • Intelephense and Phpactor for PHP • nvim-dap and nvim-dap-ui for step debugging • nvim-cmp for completion, LuaSnip for snippets • PHPCS, PHPStan diagnostics with null-ls.nvim @opdavies

Slide 44

Slide 44 text

tmux • "Terminal multiplexer" • Splits a terminal into different sessions and panes • One session per project • Editing in one pane, running commands in another • Long-running commands in a separate window @opdavies

Slide 45

Slide 45 text

Other mentions • fzf • grep and ripgrep • find and xargs • Pulumi and Terraform for infrastructure automation • Ansible and Ansistrano @opdavies

Slide 46

Slide 46 text

Thanks! References: • https://opdavi.es/dotfiles • https://nixos.org • https://just.systems • https://neovim.io • https://github.com/tmux/tmux/wiki • https://opdavi.es/docker-examples @opdavies

Slide 47

Slide 47 text

Me: • https://www.oliverdavies.uk @opdavies