#!/bin/bash
#
set -e
echo (){
    /bin/echo "#########################################"
    /bin/echo "$@"
    /bin/echo "#########################################"
}
#LICENSE#{{{
# Copyright (c) 2012 Tom Wambold
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#}}}
# CONFIGURE THESE VARIABLES{{{
# Drive to install to.
DRIVE='/dev/sda'

# Hostname of the installed machine.
HOSTNAME='arch'

# Encrypt everything (except /boot). true or false
ENCRYPT_DRIVE=true

# Passphrase used to encrypt the drive (leave blank to be prompted).
DRIVE_PASSPHRASE=''

# Root password (leave blank to be prompted).
ROOT_PASSWORD=''

# Main user to create (by default, added to wheel group, and others).
USER_NAME='lelgenio'
# Link to users dotfiles repo(git)
# Assumed to have stow-able modules on its root(cd .dotfiles;stow*/)
DOTFILES_URL="https://gitlab.com/$USER_NAME/dotfiles"
USER_SHELL='fish'

# The main user's password (leave blank to be prompted).
USER_PASSWORD=''

# System timezone.
TIMEZONE='America/Sao_Paulo'

# Country code for pacman repos
COUNTRY='brazil'

# Have /tmp on a tmpfs or not.  Leave blank to disable.
# Only leave this blank on systems with very little RAM.
TMP_ON_TMPFS='TRUE'

KEYMAP='br-abnt2'
# KEYMAP='dvorak'

LANG=pt_BR.UTF-8

#}}}
# Initial Setup{{{
# Base install{{{
setup() {
    local boot_dev="$DRIVE"1

    if "$ENCRYPT_DRIVE"
    then
        local crypt_dev="$DRIVE"2
        local lvm_dev="/dev/mapper/lvm"
    else
        local lvm_dev="$DRIVE"2
    fi

    echo 'Cleaning disk'
    disk_clean "$lvm_dev" "$DRIVE"2

    echo 'Creating partitions'
    partition_drive "$DRIVE"

    if "$ENCRYPT_DRIVE"
    then

        if [ -z "$DRIVE_PASSPHRASE" ];then
            echo 'Enter a passphrase to encrypt the disk:'
            read -s DRIVE_PASSPHRASE
        fi

        echo 'Encrypting partition'
        encrypt_drive "$crypt_dev" "$DRIVE_PASSPHRASE" lvm
    fi

    echo 'Setting up LVM'
    setup_lvm "$lvm_dev" vg00

    echo 'Formatting filesystems'
    format_filesystems "$boot_dev"

    echo 'Mounting filesystems'
    mount_filesystems "$boot_dev"

    echo 'Setting repos'
    set_repos

    echo 'Installing base system'
    install_base

    echo 'Setting fstab'
    set_fstab

    echo 'Chrooting into installed system to continue setup...'
    cp "$0" "/mnt/setup.sh"
    chmod +x "/mnt/setup.sh"
    arch-chroot /mnt "./setup.sh"

    if [ -f  "/mnt/setup.sh" ];then
        echo 'ERROR: Something failed inside the chroot, not unmounting filesystems so you can investigate.'
        echo 'Make sure you unmount everything before you try to run this script again.'
    else
        echo 'Unmounting filesystems'
        unmount_filesystems
        echo 'Done! Reboot system.'
    fi
}
#}}}
# Remove old LVMs{{{
disk_clean(){

    local lvm_dev="$1"
    local disk="$2"

    echo 'cleaning disk'

    umount --recursive --quiet /mnt || true
    swapoff -a

    pvs "$lvm_dev" || return 0

    for vg in $(pvs -o vg_name --nohead "$lvm_dev")
    do
        vgremove "$vg" --yes
    done

    pvremove "$lvm_dev"

    if "$ENCRYPT_DRIVE"
    then
        cryptsetup close lvm
    fi

    wipefs -a "$disk"

}
#}}}
# Partition Drive{{{
partition_drive() {
    local dev="$1"; shift

    # 100 MB /boot partition, everything else under LVM
    if $IS_BIOS;then
        parted  \
            --align optimal \
            --script "$dev" \
            mklabel msdos \
            mkpart primary fat32 1M   100M \
            mkpart primary ext4  100M 100% \
            set 1 boot on \
            set 2 lvm  on
    else
        parted \
            --align optimal \
            --script "$dev" \
            mklabel gpt \
            mkpart boot 1    100M \
            mkpart lvm  100M 100% \
            set 1 boot on \
            set 2 lvm  on
    fi
}
#}}}
# Encrypt_drive {{{
encrypt_drive() {
    local dev="$1"; shift
    local passphrase="$1"; shift
    local name="$1"; shift

    /bin/echo -en "$passphrase" | cryptsetup luksFormat "$dev"
    /bin/echo -en "$passphrase" | cryptsetup luksOpen "$dev" lvm
}
#}}}
# setup_lvm{{{
setup_lvm() {
    local partition="$1"; shift
    local volgroup="$1"; shift

    local d_size=$(lsblk --noheadings --nodeps --bytes --raw --output SIZE $DRIVE)

    local swap_size=$(free -b | awk '/^Mem/ { printf "%.0fG", 2*$2*10**-9}')

    pvcreate "$partition"
    vgcreate "$volgroup" "$partition"

    # Create a swap partition that is twice the amount of RAM
    lvcreate --yes -L$swap_size "$volgroup" -n swap

    # if the disk has more than 100Gb
    if [ "$d_size" -gt $( echo "100*10^9" | bc ) ]
    then
        # Create a 50GB root partition
        lvcreate --yes -L '50G' "$volgroup" -n root
    else
        # Create root partition on 50% of free space
        lvcreate --yes -l '+50%FREE' "$volgroup" -n root
    fi

    # Use the rest of the space for home
    lvcreate --yes -l '+100%FREE' "$volgroup" -n home

    # Enable the new volumes
    vgchange -ay

}
#}}}
# format_filesystems #{{{
format_filesystems() {
    local boot_dev="$1"; shift

    mkfs.fat  "$boot_dev"
    mkfs.ext4 -L root /dev/vg00/root
    mkfs.ext4 -L home /dev/vg00/home
    mkswap /dev/vg00/swap
}
#}}}
# mount_filesystems #{{{
mount_filesystems() {
    local boot_dev="$1"; shift

    mount /dev/vg00/root /mnt
    mkdir /mnt/home
    mount /dev/vg00/home /mnt/home
    mkdir /mnt/boot
    mount "$boot_dev" /mnt/boot
    swapon /dev/vg00/swap
}
#}}}
# set_repos() {{{{
set_repos() {
    # /etc/pacman.conf{{{
    cat > /etc/pacman.conf <<EOF
#
# GENERAL OPTIONS
#
[options]
HoldPkg     = pacman glibc
Architecture = auto

# Misc options
#UseSyslog
Color
ILoveCandy
#TotalDownload
CheckSpace
#VerbosePkgLists

SigLevel    = Required DatabaseOptional
LocalFileSigLevel = Optional
#RemoteFileSigLevel = Required

#
# REPOSITORIES
#

#[testing]
#Include = /etc/pacman.d/mirrorlist

[core]
Include = /etc/pacman.d/mirrorlist

[extra]
Include = /etc/pacman.d/mirrorlist

#[community-testing]
#Include = /etc/pacman.d/mirrorlist

[community]
Include = /etc/pacman.d/mirrorlist


#[multilib-testing]
#Include = /etc/pacman.d/mirrorlist

[multilib]
Include = /etc/pacman.d/mirrorlist

EOF
#}}}
# /etc/pacman.d/mirrorlist{{{
    pacman -Sy reflector --noconfirm --needed

    reflector -c $COUNTRY -f 10 -p http -p https
#}}}

mkdir -p /mnt/etc/pacman.d
cp -r /mnt/etc/pacman* /etc/
}
#}}}
# install_base #{{{
install_base() {
    pacstrap /mnt \
        base base-devel linux-zen linux-firmware intel-ucode grub \
        fish bluez cronie git man-db \
        iwd dhcpcd
}
#}}}
# Set fstab {{{
set_fstab() {
    genfstab -Up /mnt > /mnt/etc/fstab
}
#}}}
# Unmount filesystems #{{{
unmount_filesystems() {
    umount -R /mnt
    swapoff /dev/vg00/swap
    vgchange -an
    if $ENCRYPT_DRIVE
    then
        cryptsetup luksClose lvm
    fi
}
#}}}
# is_bios{{{
    if ls /sys/firmware/efi/efivars/ &> /dev/null
    then
        IS_BIOS=false
    else
        IS_BIOS=true
    fi
#}}}
#}}}
# Configuration{{{
# configure() {#{{{
configure() {
    local boot_dev="$DRIVE"1
    local lvm_dev="$DRIVE"2

    echo 'Setting hostname'
    set_hostname "$HOSTNAME"

    echo 'Setting timezone'
    set_timezone "$TIMEZONE"

    echo 'Setting locale'
    set_locale

    echo 'Setting console keymap'
    set_inputs

    echo 'Configuring initial ramdisk'
    set_initcpio

    echo 'Configuring Bluetooth'
    set_bluetooth

    echo 'Configuring bootloader'
    set_bootctl "$boot_dev" "$lvm_dev"

    echo 'Configuring sudo'
    set_sudoers

    echo 'Configuring PAM'
    set_pam

    echo 'Configuring logind'
    set_logind

    if [ -z "$ROOT_PASSWORD" ];then
        echo 'Enter the root password:'
        read -s ROOT_PASSWORD
    fi

    echo 'Setting root password'
    set_root_password "$ROOT_PASSWORD"

    if [ -z "$USER_PASSWORD" ];then
        echo "Enter the password for user $USER_NAME"
        read -s USER_PASSWORD
    fi

    echo 'Creating initial user'
    create_user "$USER_NAME" "$USER_PASSWORD"

    echo 'setting up user'
    cp $0 "/home/$USER_NAME/setup.sh"
    chown $USER_NAME "/home/$USER_NAME/setup.sh"
    su $USER_NAME -c "/home/$USER_NAME/setup.sh"

    shred   "/home/$USER_NAME/setup.sh"
    rm      "/home/$USER_NAME/setup.sh"

    echo 'Setting initial daemons'
    set_daemons "$TMP_ON_TMPFS"

    echo 'Updating pkgfile database'
    update_pkgfile

}
#}}}
# set_hostname() {#{{{
set_hostname() {
    local hostname="$1"; shift

    /bin/echo "$hostname" > /etc/hostname

    cat > /etc/hosts <<EOF
127.0.0.1 localhost.localdomain localhost $hostname
::1       localhost.localdomain localhost $hostname
EOF
}
#}}}
# set_timezone() {#{{{
set_timezone() {
    local timezone="$1"; shift

    ln -sfT "/usr/share/zoneinfo/$TIMEZONE" /etc/localtime

    timedatectl set-ntp on

    hwclock --systohc || echo FAILED TO SET HW CLOCK
}
#}}}
# set_locale() {#{{{
set_locale() {
    cat > /etc/locale.conf <<EOF
LANG=$LANG
LC_COLLATE=C
EOF

    cat > /etc/locale.gen <<EOF
en_US.UTF-8 UTF-8
$LANG       UTF-8
EOF

    locale-gen
}
#}}}
# set_inputs() {#{{{
set_inputs() {
    localectl set-keymap $KEYMAP
    mkdir -p /etc/X11/xorg.conf.d/
    cat > /etc/X11/xorg.conf.d/30-touchpad.conf <<EOF
Section "InputClass"
    MatchIsTouchpad "on"
    Identifier "devname"
    Driver "libinput"
    Option "Tapping" "on"
    Option "ClickMethod" "clickfinger"
    Option "NaturalScrolling" "true"
EndSection
EOF

}
#}}}
# set_initcpio() {#{{{
set_initcpio() {
    local vid

    if [ "$VIDEO_DRIVER" = "i915" ];then
        vid='i915'
    elif [ "$VIDEO_DRIVER" = "nouveau" ];then
        vid='nouveau'
    elif [ "$VIDEO_DRIVER" = "radeon" ];then
        vid='radeon'
    fi

    local encrypt=""
    if $ENCRYPT_DRIVE
    then
        encrypt="encrypt keyboard"
    fi

    cat > /etc/mkinitcpio.conf <<EOF
# vim:set ft=sh
MODULES=(ext4 $vid)

BINARIES=()

FILES=()

HOOKS=(base udev autodetect block $encrypt lvm2 filesystems fsck)

EOF

    # Intall kernel, if necessary
    [ -f /boot/vmlinuz-linux-zen ] ||
        mkinitcpio -P
}
#}}}
# set_daemons() {#{{{
set_daemons() {
    local tmp_on_tmpfs="$1"; shift
    if [ -z "$tmp_on_tmpfs" ];then
        systemctl mask tmp.mount
    fi

    systemctl enable \
        cronie.service  \
        iwd.service     \
        dhcpcd.service  \
        ly.service      \

# Ly{{{
    mkdir -p /etc/ly/
    cat > /etc/ly/config.ini << EOF
animate = true
blank_box = true
hide_borders = true
lang = br
EOF
#}}}
}
#}}}
# set_bluetooth{{{
set_bluetooth() {
    mkdir -p /etc/bluetooth/
    cat > /etc/bluetooth/main.conf <<EOF

[General]
DiscoverableTimeout = 0
Discoverable = true

AlwaysPairable = true

[Policy]
AutoEnable=true

EOF
}
#}}}
# set_boot_loader() {{{
set_bootctl() {
    local boot_dev="$1"; shift
    local lvm_dev="$1"; shift

    local lvm_uuid=$(get_uuid "/dev/vg00/root")

    local k_args="root=UUID=$lvm_uuid"

    if $IS_BIOS;then
        cat >> /etc/default/grub <<EOF
GRUB_CMDLINE_LINUX_DEFAULT="$k_args"
# GRUB_CMDLINE_LINUX_DEFAULT="quiet splash loglevel=3 vga=current rd.udev.log_priority=3 rd.systemd.show_status=auto vt.global_cursor_default=0 nmi_watchdog=0 $k_args"
EOF

        grub-install "$DRIVE"
        grub-mkconfig -o /boot/grub/grub.cfg
    else
        bootctl install
        cat > /boot/loader/entries/arch.conf <<EOF
title arch

linux vmlinuz-linux-zen
initrd intel-ucode.img
initrd initramfs-linux-zen.img

options $k_args
# options quiet splash loglevel=3 vga=current rd.udev.log_priority=3 rd.systemd.show_status=auto vt.global_cursor_default=0 nmi_watchdog=0
EOF

    fi
}
#}}}
# set_sudoers() {#{{{
set_sudoers() {
    cat > /etc/sudoers <<EOF
##
## User privilege specification
##
root ALL=(ALL) ALL

## Uncomment to allow members of group wheel to execute any command
# %wheel ALL=(ALL) ALL

## Same thing without a password
%wheel ALL=(ALL) NOPASSWD: ALL


## Read drop-in files from /etc/sudoers.d
## (the '#' here does not indicate a comment)
#includedir /etc/sudoers.d
EOF

    chmod 440 /etc/sudoers
}
#}}}
# set_pam{{{
set_pam() {
    cat > /etc/pam.d/system-local-login <<EOF
auth      include   system-login
account   include   system-login
password  include   system-login
session   include   system-login

auth       optional  	pam_gnupg.so
session    optional  	pam_gnupg.so
EOF

}
#}}}
# set_logind{{{
set_logind(){
    mkdir -p /etc/systemd
    cat > /etc/systemd/logind.conf <<EOF
[Login]
HandlePowerKey=suspend
HandleSuspendKey=suspend
HandleLidSwitch=ignore
EOF
}
#}}}
# set_root_password() {#{{{
set_root_password() {
    local password="$1"; shift

    /bin/echo -en "$password\n$password" | passwd
}
#}}}
# create_user() {#{{{
create_user() {
    local name="$1"; shift
    local password="$1"; shift

    grep "^$name" /etc/passwd ||
        useradd -m -s /usr/bin/$USER_SHELL -G adm,systemd-journal,wheel,rfkill,games,network,video,audio,optical,floppy,storage,scanner,power,input "$name"
    /bin/echo -en "$password\n$password" | passwd "$name"
}
#}}}
# update_pkgfile() {#{{{
update_pkgfile() {
    pkgfile -u
}
#}}}
# get_uuid() {#{{{
get_uuid() {
    lsblk --noheadings --nodeps --output UUID "$1"
}
#}}}
# is_chroot(){{{{
is_chroot(){
    test "$(ls -id / | cut -d' ' -f1)" == "2"
}
#}}}
#}}}
# User setup{{{
user_setup() {

    echo 'Installing packages'
    install_aur_packages

    echo 'Installing dotfiles'
    install_dots
}
# Install AUR helper #{{{
install_aur_packages() {

    sudo pacman -S --needed git

    # getting yay
    if ! command -v yay
    then
        git clone http://aur.archlinux.org/yay.git ~/yay
        cd ~/yay
        makepkg -si --noconfirm
        cd -
    fi
}
#}}}
# Install dotfiles{{{
install_dots() {
    if [ ! -d  ~/.dotfiles ];then
        git clone $DOTFILES_URL ~/.dotfiles
    fi
    if [ -f ~/.dotfiles/config.y*ml ]; then
        dotdrop --cfg ~/.dotfiles/config.y*ml install --force --no-banner
    fi
}
#}}}
#}}}

if [ ! "$USER" == "root"  ];then
    user_setup
elif is_chroot;then
    configure
else
    setup
fi

# vim:foldmethod=marker
