Compare commits
No commits in common. "main" and "0.4" have entirely different histories.
26 changed files with 246 additions and 1017 deletions
24
.github/ISSUE_TEMPLATE/bug_report.md
vendored
24
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
|
@ -1,24 +0,0 @@
|
||||||
---
|
|
||||||
name: Bug report
|
|
||||||
about: Create a report to help us improve
|
|
||||||
title: ''
|
|
||||||
labels: ''
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Describe the bug**
|
|
||||||
A clear and concise description of what the bug is.
|
|
||||||
|
|
||||||
**To Reproduce**
|
|
||||||
Steps to reproduce the behavior:
|
|
||||||
1. Go to '...'
|
|
||||||
2. Click on '....'
|
|
||||||
3. Scroll down to '....'
|
|
||||||
4. See error
|
|
||||||
|
|
||||||
**Expected behavior**
|
|
||||||
A clear and concise description of what you expected to happen.
|
|
||||||
|
|
||||||
**Additional context**
|
|
||||||
Add any other context about the problem here.
|
|
||||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
|
|
@ -1,20 +0,0 @@
|
||||||
---
|
|
||||||
name: Feature request
|
|
||||||
about: Suggest an idea for this project
|
|
||||||
title: ''
|
|
||||||
labels: ''
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Is your feature request related to a problem? Please describe.**
|
|
||||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
|
||||||
|
|
||||||
**Describe the solution you'd like**
|
|
||||||
A clear and concise description of what you want to happen.
|
|
||||||
|
|
||||||
**Describe alternatives you've considered**
|
|
||||||
A clear and concise description of any alternative solutions or features you've considered.
|
|
||||||
|
|
||||||
**Additional context**
|
|
||||||
Add any other context or screenshots about the feature request here.
|
|
||||||
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
|
@ -1,3 +0,0 @@
|
||||||
- [ ] Closes #xxxx
|
|
||||||
- [ ] Tests added / passed
|
|
||||||
- [ ] All linting tests pass
|
|
||||||
28
.github/workflows/docs.yml
vendored
28
.github/workflows/docs.yml
vendored
|
|
@ -1,28 +0,0 @@
|
||||||
name: Docs
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Install Python
|
|
||||||
uses: actions/setup-python@v1
|
|
||||||
with:
|
|
||||||
python-version: 3.9
|
|
||||||
- name: Install dependencies
|
|
||||||
run: python -m pip install --upgrade pip sphinx
|
|
||||||
- name: Build docs
|
|
||||||
run: sphinx-build -a docs/source docs/build
|
|
||||||
- name: Deploy
|
|
||||||
uses: peaceiris/actions-gh-pages@v3
|
|
||||||
with:
|
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
publish_dir: ./docs/build
|
|
||||||
publish_branch: gh-pages
|
|
||||||
24
.github/workflows/tests.yml
vendored
24
.github/workflows/tests.yml
vendored
|
|
@ -1,24 +0,0 @@
|
||||||
name: Tests
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Install Python
|
|
||||||
uses: actions/setup-python@v1
|
|
||||||
with:
|
|
||||||
python-version: 3.9
|
|
||||||
- name: Install dependencies
|
|
||||||
run: python -m pip install --upgrade pip pytest flake8
|
|
||||||
- name: Run linter
|
|
||||||
run: flake8 --max-line-length=120 scripts/
|
|
||||||
- name: Run tests
|
|
||||||
run: python -m pytest -v
|
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -1,4 +0,0 @@
|
||||||
__pycache__
|
|
||||||
venv
|
|
||||||
docs/build
|
|
||||||
man8
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
# snap-pac
|
# snap-pac
|
||||||
# https://github.com/wesbarnett/snap-pac
|
# Copyright (C) 2016 James W. Barnett
|
||||||
# Copyright (C) 2016, 2017, 2018 James W. Barnett
|
|
||||||
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# This program is free software; you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
|
@ -17,12 +16,14 @@
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
[Trigger]
|
[Trigger]
|
||||||
|
Operation = Upgrade
|
||||||
|
Operation = Install
|
||||||
Operation = Remove
|
Operation = Remove
|
||||||
Type = Package
|
Type = Package
|
||||||
Target = snap-pac
|
Target = *
|
||||||
|
|
||||||
[Action]
|
[Action]
|
||||||
Description = You are removing snap-pac. No post transaction snapshots will be taken.
|
Description = snapper post snapshot
|
||||||
Depends = snap-pac
|
Depends = snapper
|
||||||
When = PreTransaction
|
When = PostTransaction
|
||||||
Exec = /usr/bin/bash -c "rm -f /tmp/snap-pac-pre_*"
|
Exec = /usr/share/libalpm/hooks.bin/snap-pac/snapper-post
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
# snap-pac
|
# snap-pac
|
||||||
# https://github.com/wesbarnett/snap-pac
|
# Copyright (C) 2016 James W. Barnett
|
||||||
# Copyright (C) 2016, 2017, 2018 James W. Barnett
|
|
||||||
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# This program is free software; you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
|
@ -24,9 +23,7 @@ Type = Package
|
||||||
Target = *
|
Target = *
|
||||||
|
|
||||||
[Action]
|
[Action]
|
||||||
Description = Taking snapper snapshot before installing...
|
Description = snapper pre snapshot
|
||||||
Depends = snap-pac
|
Depends = snapper
|
||||||
When = PreTransaction
|
When = PreTransaction
|
||||||
Exec = /usr/share/libalpm/scripts/snap-pac
|
Exec = /usr/share/libalpm/hooks.bin/snap-pac/snapper-pre
|
||||||
NeedsTargets
|
|
||||||
AbortOnFail
|
|
||||||
29
99_grub-config.hook
Normal file
29
99_grub-config.hook
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
# snap-pac
|
||||||
|
# Copyright (C) 2016 James W. Barnett
|
||||||
|
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU General Public License along
|
||||||
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
[Trigger]
|
||||||
|
Operation = Upgrade
|
||||||
|
Operation = Install
|
||||||
|
Operation = Remove
|
||||||
|
Type = Package
|
||||||
|
Target = *
|
||||||
|
|
||||||
|
[Action]
|
||||||
|
Description = generate GRUB configuration file
|
||||||
|
Depends = grub
|
||||||
|
When = PostTransaction
|
||||||
|
Exec = /usr/share/libalpm/hooks.bin/snap-pac/grub-config
|
||||||
42
Makefile
42
Makefile
|
|
@ -1,42 +0,0 @@
|
||||||
# snap-pac
|
|
||||||
# https://github.com/wesbarnett/snap-pac
|
|
||||||
# Copyright (C) 2016-2021 James W. Barnett
|
|
||||||
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation; either version 2 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
|
|
||||||
# You should have received a copy of the GNU General Public License along
|
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
|
|
||||||
PKGNAME = snap-pac
|
|
||||||
PREFIX ?= /usr
|
|
||||||
|
|
||||||
SHARE_DIR = $(DESTDIR)$(PREFIX)/share
|
|
||||||
|
|
||||||
.PHONY: install test docs
|
|
||||||
|
|
||||||
install: man
|
|
||||||
@install -Dm755 scripts/snap_pac.py $(SHARE_DIR)/libalpm/scripts/snap-pac
|
|
||||||
@install -Dm644 hooks/* -t $(SHARE_DIR)/libalpm/hooks/
|
|
||||||
@install -Dm644 LICENSE -t $(SHARE_DIR)/licenses/$(PKGNAME)/
|
|
||||||
@install -Dm644 man8/* -t $(SHARE_DIR)/man/man8/
|
|
||||||
@install -Dm644 README.md -t $(SHARE_DIR)/doc/$(PKGNAME)/
|
|
||||||
@install -Dm644 extra/snap-pac.ini $(DESTDIR)/etc/snap-pac.ini
|
|
||||||
|
|
||||||
test:
|
|
||||||
@python -m pytest -v .
|
|
||||||
|
|
||||||
man:
|
|
||||||
@cd docs && make man
|
|
||||||
@mkdir -p man8
|
|
||||||
@awk 'NR==33{print ".SH DESCRIPTION"}7' docs/build/man/snap-pac.8 > man8/snap-pac.8
|
|
||||||
|
|
||||||
docs: man
|
|
||||||
@sphinx-build -a docs/source docs/build
|
|
||||||
141
README.md
141
README.md
|
|
@ -1,25 +1,142 @@
|
||||||
# snap-pac
|
# snap-pac
|
||||||
|
|
||||||
## Synopsis
|
This makes Arch Linux's pacman use
|
||||||
|
[snapper](https://wiki.archlinux.org/index.php/Snapper) to automatically take a
|
||||||
|
pre and post snapshot before and after pacman transactions, similar to how YaST
|
||||||
|
does with OpenSuse. This provides a simple way to undo changes to a system after
|
||||||
|
a pacman transaction.
|
||||||
|
|
||||||
This is a set of [pacman](https://wiki.archlinux.org/index.php/Pacman) hooks and scripts that automatically cause [snapper](http://snapper.io/) to perform a snapshot before pacman transactions.
|
The snapshots are set up to use snapper's `number` algorithm. That is, snapper
|
||||||
|
will periodically clean up snapshots tagged with `number` after reaching a set
|
||||||
|
threshold in the snapper configuration file.
|
||||||
|
|
||||||
Forked from Wes Barnett's solution for my own personal needs. Takes a single screenshot vs. the original's pre/post pair.
|
Additionally the package provides a hook to regenerate your GRUB configuration
|
||||||
|
file after every pacman transaction. This is useful when using
|
||||||
|
[grub-btrfs](https://aur.archlinux.org/packages/grub-btrfs-git/). If you don't
|
||||||
|
use GRUB, or if you don't want your configuration file generated every
|
||||||
|
transaction, then you should remove `99_grub-config.hook` after installation.
|
||||||
|
|
||||||
## [Installation](https://wesbarnett.github.io/snap-pac/installation.html)
|
**Note:** Snapshots are only taken of the subvolume corresponding with the
|
||||||
|
`root` snapper config; other subvolumes are not included. You must modify the
|
||||||
|
scripts to include other subvolumes. Additionally, you should create subvolumes
|
||||||
|
of directories you do *not* want included in your snapshots (*e.g.*
|
||||||
|
`/var/cache/pacman/pkg`).
|
||||||
|
|
||||||
## Configuration
|
## Installation
|
||||||
|
|
||||||
Most likely, configuration is not needed. By default, the snapper configuration named `root` will have snapshots taken before every pacman transaction.
|
Install [the package from the
|
||||||
|
AUR](https://aur.archlinux.org/packages/snap-pac/).
|
||||||
|
|
||||||
For more information on configuring snap-pac, see [the documentation](https://wesbarnett.github.io/snap-pac/configuration.html).
|
Optionally, install
|
||||||
|
[grub-btrfs](https://aur.archlinux.org/packages/grub-btrfs-git/) to populate
|
||||||
|
your GRUB menu with the ability to boot into snapshots.
|
||||||
|
|
||||||
## Documentation
|
After installation, the hooks are located at `/usr/share/libalpm/hooks` and the
|
||||||
|
scripts are located at `/usr/share/libalpm/hooks.bin/snap-pac`.
|
||||||
|
|
||||||
See the [documentation here](https://wesbarnett.github.io/snap-pac/) or `man 8 snap-pac` after installation.
|
## Usage
|
||||||
|
|
||||||
## Troubleshooting
|
### Taking snapshots
|
||||||
|
|
||||||
After reviewing the documentation, [check the issues page] and file a new issue if your problem is not covered.
|
**Use pacman—and AUR helpers—as normal and watch snapper do its thing.** No
|
||||||
|
bash scripts for you to call. No bash aliases to setup.
|
||||||
|
|
||||||
[check the issues page]: https://codeberg.org/ak95/snap-pac/issues
|
Because these are pacman hooks, it doesn't matter how you call pacman—whether
|
||||||
|
directly, through an AUR helper, or using an alias—snapper will create the
|
||||||
|
snapshots when pacman installs, upgrades, or removes a package. The
|
||||||
|
pacman command used is logged in the snapper description for the
|
||||||
|
snapshots.
|
||||||
|
|
||||||
|
### Undoing a transaction
|
||||||
|
|
||||||
|
To undo changes from a pacman transaction, use `snapper undochange`. See the
|
||||||
|
snapper manpage and the following example.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
Installing the `nano` package as normal:
|
||||||
|
|
||||||
|
# pacman -S nano
|
||||||
|
resolving dependencies...
|
||||||
|
looking for conflicting packages...
|
||||||
|
|
||||||
|
Packages (1) nano-2.5.3-1
|
||||||
|
|
||||||
|
Total Installed Size: 2.14 MiB
|
||||||
|
|
||||||
|
:: Proceed with installation? [Y/n] Y
|
||||||
|
(1/1) checking keys in keyring [######################################] 100%
|
||||||
|
(1/1) checking package integrity [######################################] 100%
|
||||||
|
(1/1) loading package files [######################################] 100%
|
||||||
|
(1/1) checking for file conflicts [######################################] 100%
|
||||||
|
(1/1) checking available disk space [######################################] 100%
|
||||||
|
:: Running pre-transaction hooks...
|
||||||
|
(1/1) snapper pre snapshot
|
||||||
|
:: Processing package changes...
|
||||||
|
(1/1) installing nano [######################################] 100%
|
||||||
|
:: Running post-transaction hooks...
|
||||||
|
(1/2) snapper post snapshot
|
||||||
|
(2/2) generate GRUB configuration file
|
||||||
|
|
||||||
|
And here are the snapshots:
|
||||||
|
|
||||||
|
# snapper -c root list -t pre-post | tail -n 1
|
||||||
|
1033 | 1034 | Fri 22 Apr 2016 01:54:13 PM CDT | Fri 22 Apr 2016 01:54:14 PM CDT | pacman -S nano |
|
||||||
|
|
||||||
|
What changed?
|
||||||
|
|
||||||
|
# snapper -c root status 1033..1034
|
||||||
|
+..... /etc/nanorc
|
||||||
|
c..... /etc/snapper/.snap-pac-pre
|
||||||
|
+..... /usr/bin/nano
|
||||||
|
+..... /usr/bin/rnano
|
||||||
|
+..... /usr/share/doc/nano
|
||||||
|
+..... /usr/share/doc/nano/faq.html
|
||||||
|
+..... /usr/share/doc/nano/fr
|
||||||
|
+..... /usr/share/doc/nano/fr/nano.1.html
|
||||||
|
+..... /usr/share/doc/nano/fr/nanorc.5.html
|
||||||
|
+..... /usr/share/doc/nano/fr/rnano.1.html
|
||||||
|
|
||||||
|
|
||||||
|
I truncated the above output, but it continues. See the manpage for snapper to
|
||||||
|
see what each symbol means. You can also do `snapper diff` in the same
|
||||||
|
way—I'll spare you that one.
|
||||||
|
|
||||||
|
To undo the upgrade:
|
||||||
|
|
||||||
|
# snapper -c root undochange 1033..1034
|
||||||
|
create:0 modify:3 delete:100
|
||||||
|
|
||||||
|
And `nano` is now gone, along with all the files it changed:
|
||||||
|
|
||||||
|
$ pacman -Qi nano
|
||||||
|
error: package 'nano' was not found
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
* [snapper homepage](http://snapper.io/)
|
||||||
|
* [Btrfs homepage](https://wiki.archlinux.org/index.php/Btrfs)
|
||||||
|
* [ArchWiki Snapper article](https://wiki.archlinux.org/index.php/Snapper)
|
||||||
|
* [ArchWiki Btrfs article](https://wiki.archlinux.org/index.php/Btrfs)
|
||||||
|
* `man alpm-hooks`
|
||||||
|
* `man snapper`
|
||||||
|
* `man btrfs`
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
snap-pac
|
||||||
|
Copyright (C) 2016 James W. Barnett
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
# Minimal makefile for Sphinx documentation
|
|
||||||
#
|
|
||||||
|
|
||||||
# You can set these variables from the command line, and also
|
|
||||||
# from the environment for the first two.
|
|
||||||
SPHINXOPTS ?=
|
|
||||||
SPHINXBUILD ?= sphinx-build
|
|
||||||
SOURCEDIR = source
|
|
||||||
BUILDDIR = build
|
|
||||||
|
|
||||||
# Put it first so that "make" without argument is like "make help".
|
|
||||||
help:
|
|
||||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
||||||
|
|
||||||
.PHONY: help Makefile
|
|
||||||
|
|
||||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
|
||||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
|
||||||
%: Makefile
|
|
||||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
@ECHO OFF
|
|
||||||
|
|
||||||
pushd %~dp0
|
|
||||||
|
|
||||||
REM Command file for Sphinx documentation
|
|
||||||
|
|
||||||
if "%SPHINXBUILD%" == "" (
|
|
||||||
set SPHINXBUILD=sphinx-build
|
|
||||||
)
|
|
||||||
set SOURCEDIR=source
|
|
||||||
set BUILDDIR=build
|
|
||||||
|
|
||||||
if "%1" == "" goto help
|
|
||||||
|
|
||||||
%SPHINXBUILD% >NUL 2>NUL
|
|
||||||
if errorlevel 9009 (
|
|
||||||
echo.
|
|
||||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
|
||||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
|
||||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
|
||||||
echo.may add the Sphinx directory to PATH.
|
|
||||||
echo.
|
|
||||||
echo.If you don't have Sphinx installed, grab it from
|
|
||||||
echo.http://sphinx-doc.org/
|
|
||||||
exit /b 1
|
|
||||||
)
|
|
||||||
|
|
||||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
|
||||||
goto end
|
|
||||||
|
|
||||||
:help
|
|
||||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
|
||||||
|
|
||||||
:end
|
|
||||||
popd
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
# Configuration file for the Sphinx documentation builder.
|
|
||||||
#
|
|
||||||
# This file only contains a selection of the most common options. For a full
|
|
||||||
# list see the documentation:
|
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
|
||||||
|
|
||||||
# -- Path setup --------------------------------------------------------------
|
|
||||||
|
|
||||||
# If extensions (or modules to document with autodoc) are in another directory,
|
|
||||||
# add these directories to sys.path here. If the directory is relative to the
|
|
||||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
|
||||||
#
|
|
||||||
# import os
|
|
||||||
# import sys
|
|
||||||
# sys.path.insert(0, os.path.abspath('.'))
|
|
||||||
|
|
||||||
|
|
||||||
# -- Project information -----------------------------------------------------
|
|
||||||
|
|
||||||
project = 'snap-pac'
|
|
||||||
copyright = '2021, Wes Barnett, PhD'
|
|
||||||
author = 'Wes Barnett, PhD'
|
|
||||||
|
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
|
||||||
|
|
||||||
# Add any Sphinx extension module names here, as strings. They can be
|
|
||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
|
||||||
# ones.
|
|
||||||
extensions = [
|
|
||||||
]
|
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
|
||||||
templates_path = ['_templates']
|
|
||||||
|
|
||||||
# List of patterns, relative to source directory, that match files and
|
|
||||||
# directories to ignore when looking for source files.
|
|
||||||
# This pattern also affects html_static_path and html_extra_path.
|
|
||||||
exclude_patterns = []
|
|
||||||
|
|
||||||
|
|
||||||
# -- Options for HTML output -------------------------------------------------
|
|
||||||
|
|
||||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
|
||||||
# a list of builtin themes.
|
|
||||||
#
|
|
||||||
html_theme = 'alabaster'
|
|
||||||
|
|
||||||
# Add any paths that contain custom static files (such as style sheets) here,
|
|
||||||
# relative to this directory. They are copied after the builtin static files,
|
|
||||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
|
||||||
html_static_path = ['_static']
|
|
||||||
|
|
||||||
html_theme_options = {
|
|
||||||
'badge_branch': 'main',
|
|
||||||
'description': 'pacman hooks that use snapper to create pre/post btrfs snapshots',
|
|
||||||
'fixed_sidebar': True,
|
|
||||||
'github_banner': True,
|
|
||||||
'github_user': 'wesbarnett',
|
|
||||||
'github_repo': 'snap-pac',
|
|
||||||
'github_type': 'star'
|
|
||||||
}
|
|
||||||
|
|
||||||
man_pages = [("index", "snap-pac", "Pacman hooks that use snapper to create pre/post btrfs snapshots like openSUSE's YaST", "Wes Barnett", "8")]
|
|
||||||
manpages_url = 'https://man.archlinux.org/man/{page}.{section}'
|
|
||||||
|
|
@ -1,99 +0,0 @@
|
||||||
Configuration
|
|
||||||
=============
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
|
|
||||||
Configuration is done via Python ini configuration files. The defaults
|
|
||||||
should be suitable for most users, so you may not need to do any configuration at all.
|
|
||||||
By default only the ``root`` snapper configuration is snapshotted.
|
|
||||||
|
|
||||||
A commented example configuration files is located at ``/etc/snap-pac.ini``.
|
|
||||||
|
|
||||||
Edit with your favorite editor. The file is commented and should be
|
|
||||||
self-explanatory.
|
|
||||||
|
|
||||||
Each section corresponds with a snapper configuration. Add additional sections to add
|
|
||||||
other snapper configurations to be snapshotted. By default, only the root configuration
|
|
||||||
is snapshotted. Additionally you can add a section named ``DEFAULT`` with options that
|
|
||||||
apply to all snapper configurations unless overridden in a later section.
|
|
||||||
|
|
||||||
Each section can have the following entries:
|
|
||||||
|
|
||||||
* ``desc_limit`` - integer; maximum length of description string before being truncated.
|
|
||||||
Default: 72
|
|
||||||
* ``important_packages`` - list of strings; names of packages that if involved in a pacman
|
|
||||||
transaction will add ``important=yes`` to the snapper userdata for the pair of
|
|
||||||
snapshots. Default: []
|
|
||||||
* ``important_commands`` - list of strings; parent commands that will add
|
|
||||||
``important=yes`` to the snapper userdata for the pair of snapshots. Default: []
|
|
||||||
* ``pre_description`` - string; description for the pre snapshot. Default: the parent
|
|
||||||
command that called the pacman hook.
|
|
||||||
* ``post_description`` - string; description for the post snapshot. Default: space
|
|
||||||
separated list of packages that were installed, upgraded, or removed.
|
|
||||||
* ``snapshot`` - boolean; whether or not to snapshot the configuration. Default: True for
|
|
||||||
``root`` configuration; False otherwise.
|
|
||||||
* ``userdata`` - list of strings; key-value pairs that will be added to the userdata for
|
|
||||||
the pair of snapshots. Default: []
|
|
||||||
|
|
||||||
Examples
|
|
||||||
--------
|
|
||||||
|
|
||||||
Turn off snapshots for ``root`` configuration and turn on for ``home`` configuration:
|
|
||||||
|
|
||||||
.. code-block:: ini
|
|
||||||
|
|
||||||
[root]
|
|
||||||
snapshot = False
|
|
||||||
|
|
||||||
[home]
|
|
||||||
snapshot = True
|
|
||||||
|
|
||||||
|
|
||||||
Set the snapper to add the userdata ``important=yes`` for every snapshot in the ``root``
|
|
||||||
configuration when a system upgrade is performed:
|
|
||||||
|
|
||||||
.. code-block:: ini
|
|
||||||
|
|
||||||
[root]
|
|
||||||
important_commands = ["pacman -Syu"]
|
|
||||||
|
|
||||||
Set the snapper to add the userdata ``important=yes`` for every snapshot in the ``root``
|
|
||||||
configuration when a pacman transaction handles the packages ``linux`` and ``linux-lts``:
|
|
||||||
|
|
||||||
.. code-block:: ini
|
|
||||||
|
|
||||||
[root]
|
|
||||||
important_packages = ["linux", "linux-lts"]
|
|
||||||
|
|
||||||
Here's a fuller example, with several options set for different configurations. In this
|
|
||||||
case the ``root`` configuration snapshot will have ``important=yes`` when ``linux`` and
|
|
||||||
``linux-lts`` packages are part of the transaction. Additionally when full system
|
|
||||||
upgrades are performed ``root`` snapshots will be marked ``important=yes``. Note that
|
|
||||||
you don't have to add ``snapshot = True`` for the ``root`` configuration since that is
|
|
||||||
the default.
|
|
||||||
|
|
||||||
This file also turns one snapshots for the ``home`` snapper configuration and adds the
|
|
||||||
userdata ``requestid=42,user=arthur`` to all snapshots for that configuration.
|
|
||||||
Additionally the post snapshot description is overridden.
|
|
||||||
|
|
||||||
.. code-block:: ini
|
|
||||||
|
|
||||||
[root]
|
|
||||||
important_packages = ["linux", "linux-lts"]
|
|
||||||
important_commands = ["pacman -Syu"]
|
|
||||||
|
|
||||||
[home]
|
|
||||||
snapshot = True
|
|
||||||
userdata = ["requestid=42", "user=arthur"]
|
|
||||||
post_description = "pacman transaction post snapshot"
|
|
||||||
|
|
||||||
Environment Variables
|
|
||||||
=====================
|
|
||||||
|
|
||||||
To temporarily prevent snapshots from being performed for a single pacman
|
|
||||||
command, set the environment variable ``SNAP_PAC_SKIP``. For example:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
sudo SNAP_PAC_SKIP=y pacman -Syu
|
|
||||||
|
|
@ -1,91 +0,0 @@
|
||||||
Example
|
|
||||||
=======
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
|
|
||||||
Here is an example of how the snapshots are created and how to rollback and pacman
|
|
||||||
transaction. Here the nano package is installed:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
pacman -S nano
|
|
||||||
|
|
||||||
.. code-block:: none
|
|
||||||
|
|
||||||
resolving dependencies...
|
|
||||||
looking for conflicting packages...
|
|
||||||
|
|
||||||
Packages (1) nano-2.5.3-1
|
|
||||||
|
|
||||||
Total Installed Size: 2.14 MiB
|
|
||||||
|
|
||||||
:: Proceed with installation? [Y/n] Y
|
|
||||||
(1/1) checking keys in keyring [######################################] 100%
|
|
||||||
(1/1) checking package integrity [######################################] 100%
|
|
||||||
(1/1) loading package files [######################################] 100%
|
|
||||||
(1/1) checking for file conflicts [######################################] 100%
|
|
||||||
(1/1) checking available disk space [######################################] 100%
|
|
||||||
:: Running pre-transaction hooks...
|
|
||||||
(1/1) Performing snapper pre snapshots for the following configurations...
|
|
||||||
=> root: 1033
|
|
||||||
:: Processing package changes...
|
|
||||||
(1/1) installing nano [######################################] 100%
|
|
||||||
:: Running post-transaction hooks...
|
|
||||||
(1/1) Performing snapper post snapshots for the following configurations...
|
|
||||||
=> root: 1034
|
|
||||||
|
|
||||||
The snapper snapshot number is given for each snapper configuration that is used. This
|
|
||||||
is also logged in pacman's log.
|
|
||||||
|
|
||||||
Here are the snapshots created before and after the pacman transaction:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
snapper -c root list -t pre-post | tail -n 1
|
|
||||||
|
|
||||||
.. code-block:: none
|
|
||||||
|
|
||||||
1033 | 1034 | Fri 22 Apr 2016 01:54:13 PM CDT | Fri 22 Apr 2016 01:54:14 PM CDT | pacman -S nano |
|
|
||||||
|
|
||||||
Here is what changed during the transaction:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
snapper -c root status 1033..1034
|
|
||||||
|
|
||||||
.. code-block:: none
|
|
||||||
|
|
||||||
+..... /etc/nanorc
|
|
||||||
c..... /etc/snapper/.snap-pac-pre
|
|
||||||
+..... /usr/bin/nano
|
|
||||||
+..... /usr/bin/rnano
|
|
||||||
+..... /usr/share/doc/nano
|
|
||||||
+..... /usr/share/doc/nano/faq.html
|
|
||||||
+..... /usr/share/doc/nano/fr
|
|
||||||
+..... /usr/share/doc/nano/fr/nano.1.html
|
|
||||||
+..... /usr/share/doc/nano/fr/nanorc.5.html
|
|
||||||
+..... /usr/share/doc/nano/fr/rnano.1.html
|
|
||||||
|
|
||||||
The above output is truncated, but it continues. See :manpage:`snapper(8)` to for what each
|
|
||||||
symbol means. You can also do ``snapper diff`` in the same way.
|
|
||||||
|
|
||||||
Then, to undo the pacman transaction:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
snapper -c root undochange 1033..1034
|
|
||||||
|
|
||||||
.. code-block:: none
|
|
||||||
|
|
||||||
create:0 modify:3 delete:100
|
|
||||||
|
|
||||||
Now nano is no longer installed, along with all the files it changed:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
pacman -Qi nano
|
|
||||||
|
|
||||||
.. code-block:: none
|
|
||||||
|
|
||||||
error: package 'nano' was not found
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
FAQ
|
|
||||||
===
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
|
|
||||||
**Does snap-pac backup non-btrfs /boot partitions?**
|
|
||||||
|
|
||||||
No, but you can add a hook that does it for you. It would be something like the following:
|
|
||||||
|
|
||||||
.. code-block:: none
|
|
||||||
|
|
||||||
[Trigger]
|
|
||||||
Operation = Upgrade
|
|
||||||
Operation = Install
|
|
||||||
Operation = Remove
|
|
||||||
Type = Package
|
|
||||||
Target = linux
|
|
||||||
|
|
||||||
[Action]
|
|
||||||
Description = Backing up /boot...
|
|
||||||
When = PreTransaction
|
|
||||||
Exec = /usr/bin/rsync -avzq --delete /boot /.bootbackup
|
|
||||||
|
|
||||||
Note that you will probably want to name the file with a numbered prefix less than
|
|
||||||
``05`` so that it is run before the snap-pac pre snapshot takes place. That will ensure
|
|
||||||
that the snapshot taken will have the boot partition back-up corresponding with the
|
|
||||||
state of the system. For example, you could name it ``04-backupboot.hook``.
|
|
||||||
|
|
||||||
|
|
||||||
**How do I link old kernel modules automatically when the kernel is upgraded?**
|
|
||||||
|
|
||||||
This behavior is no longer a part of this package. Use a pacman hook like the following:
|
|
||||||
|
|
||||||
.. code-block:: none
|
|
||||||
|
|
||||||
[Trigger]
|
|
||||||
Operation = Upgrade
|
|
||||||
Operation = Install
|
|
||||||
Operation = Remove
|
|
||||||
Type = Package
|
|
||||||
Target = linux
|
|
||||||
|
|
||||||
[Action]
|
|
||||||
Description = Symlinking old kernel modules...
|
|
||||||
When = PostTransaction
|
|
||||||
Exec = /usr/bin/bash -c "find /usr/lib/modules -xtype l -delete; ln -sv /.snapshots/$(snapper -c root list | awk 'END{print $1}')/snapshot/usr/lib/modules/$(uname -r) /usr/lib/modules/"
|
|
||||||
|
|
@ -1,79 +0,0 @@
|
||||||
.. snap-pac documentation master file, created by
|
|
||||||
sphinx-quickstart on Thu Mar 11 19:49:12 2021.
|
|
||||||
You can adapt this file completely to your liking, but it should at least
|
|
||||||
contain the root `toctree` directive.
|
|
||||||
|
|
||||||
snap-pac
|
|
||||||
========
|
|
||||||
|
|
||||||
This is a set of `pacman <https://archlinux.org/pacman/>`_ hooks and script that causes
|
|
||||||
`snapper <http://snapper.io/>`_ to automatically take a pre and post snapshot before and
|
|
||||||
after pacman transactions, similar to how `YaST <https://yast.opensuse.org/>`_ does with
|
|
||||||
OpenSuse. This provides a simple way to undo changes to a system after a pacman
|
|
||||||
transaction.
|
|
||||||
|
|
||||||
Because these are pacman hooks, it doesn't matter how you call pacman—whether
|
|
||||||
directly, through an AUR helper, or using an alias—snapper will create the snapshots
|
|
||||||
when pacman installs, upgrades, or removes a package. The pacman command used is
|
|
||||||
logged in the snapper description for the snapshots. Additionally the snapshot numbers
|
|
||||||
are output to the screen and to the pacman log for each snapper configuration during the
|
|
||||||
pacman transaction, so that the user can easily find which changes he or she may want to
|
|
||||||
revert.
|
|
||||||
|
|
||||||
.. code-block:: none
|
|
||||||
:caption: When you run pacman, the snapper pre/post snapshots are created automatically. For a fuller example see :doc:`examples`.
|
|
||||||
:emphasize-lines: 17,18,25,26
|
|
||||||
|
|
||||||
$ sudo pacman -S vim
|
|
||||||
resolving dependencies...
|
|
||||||
looking for conflicting packages...
|
|
||||||
|
|
||||||
Packages (1) vim-8.2.2489-1
|
|
||||||
|
|
||||||
Total Installed Size: 3.79 MiB
|
|
||||||
Net Upgrade Size: 0.00 MiB
|
|
||||||
|
|
||||||
:: Proceed with installation? [Y/n]
|
|
||||||
(1/1) checking keys in keyring [############] 100%
|
|
||||||
(1/1) checking package integrity [############] 100%
|
|
||||||
(1/1) loading package files [############] 100%
|
|
||||||
(1/1) checking for file conflicts [############] 100%
|
|
||||||
(1/1) checking available disk space [############] 100%
|
|
||||||
:: Running pre-transaction hooks...
|
|
||||||
(1/1) Performing snapper pre snapshots for the following configurations...
|
|
||||||
==> root: 7394
|
|
||||||
:: Processing package changes...
|
|
||||||
(1/1) installing vim [############] 100%
|
|
||||||
:: Running post-transaction hooks...
|
|
||||||
(1/4) Arming ConditionNeedsUpdate...
|
|
||||||
(2/4) Updating icon theme caches...
|
|
||||||
(3/4) Updating the desktop file MIME type cache...
|
|
||||||
(4/4) Performing snapper post snapshots for the following configurations...
|
|
||||||
==> root: 7395
|
|
||||||
|
|
||||||
|
|
||||||
To undo changes from a pacman transaction, use ``snapper undochange``. See the :manpage:`snapper(8)`
|
|
||||||
for more details as well as examples.
|
|
||||||
|
|
||||||
If you have severe breakage—like snapper is gone for some reason and you can't get it
|
|
||||||
back—you'll have to resort to more extreme methods, such as taking a snapshot of the pre
|
|
||||||
snapshot and making it the default subvolume or mounting it as /. Most likely you'll
|
|
||||||
need to use a live USB to get into a chroot environment to do any of these things.
|
|
||||||
Snapper has a ``snapper rollback`` feature, but your setup has to be properly configured to
|
|
||||||
use it. The exact procedure depends on your specific setup. Be careful.
|
|
||||||
|
|
||||||
Note that the pre transaction hooks occur before the pacman transaction but after the
|
|
||||||
pacman database is synced, if applicable. In other words, if you run `pacman -Syu` and
|
|
||||||
roll back the upgrade according to the above instructions, you will not have rolled back
|
|
||||||
the pacman database to the previous state. Thus, if, after upgrading and rolling back
|
|
||||||
the upgrade, you then install a package, it will possibly be a partial upgrade, which is
|
|
||||||
unsupported.
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 1
|
|
||||||
|
|
||||||
installation
|
|
||||||
configuration
|
|
||||||
examples
|
|
||||||
troubleshooting
|
|
||||||
faq
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
Installation
|
|
||||||
============
|
|
||||||
|
|
||||||
Install the ``snap-pac`` package using pacman:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
pacman -S snap-pac
|
|
||||||
|
|
||||||
Alternatively download the `latest release and signature
|
|
||||||
<https://github.com/wesbarnett/snap-pac/releases>`_. Then, verify the download:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
gpg --verify snap-pac-<version>.tar.gz.sig
|
|
||||||
|
|
||||||
where ``<version>`` is the version number you downloaded.
|
|
||||||
|
|
||||||
Finally, run:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
make install
|
|
||||||
|
|
||||||
I have signed the release tarball and commits with my PGP key. Starting with release
|
|
||||||
2.2, the tarballs are signed with my key with fingerprint
|
|
||||||
``F7B28C61944FE30DABEEB0B01070BCC98C18BD66``.
|
|
||||||
|
|
||||||
For previous releases, the key's fingerprint was
|
|
||||||
``8535CEF3F3C38EE69555BF67E4B5E45AA3B8C5C3``.
|
|
||||||
|
|
||||||
Dependencies
|
|
||||||
------------
|
|
||||||
|
|
||||||
``python``, ``pacman``, and ``snapper`` are all required.
|
|
||||||
|
|
||||||
Testing
|
|
||||||
-------
|
|
||||||
|
|
||||||
For testing, ``pytest`` is required. To run the tests do:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
make test
|
|
||||||
|
|
||||||
|
|
||||||
Documentation
|
|
||||||
-------------
|
|
||||||
|
|
||||||
Typically, you will not need to build the documentation on your own and can simply
|
|
||||||
access it by visiting the `online documentation
|
|
||||||
<https://wesbarnett.github.io/snap-pac/>`_ or by accessing the manpage:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
man 8 snap-pac
|
|
||||||
|
|
||||||
To build the documentation, ``sphinx`` is required. To build the documentation you can
|
|
||||||
do:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
make docs
|
|
||||||
|
|
||||||
The resulting html documentation will then be located at ``docs/build/index.html``.
|
|
||||||
Additionally, this generates the manpage which will be located under ``man8``.
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
Troubleshooting
|
|
||||||
===============
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
|
|
||||||
**snap-pac is only taking snapshots of the root configuration.**
|
|
||||||
|
|
||||||
That's the default behavior. See :doc:`configuration`.
|
|
||||||
|
|
||||||
**No snapshots are being taken when I run pacman.**
|
|
||||||
|
|
||||||
No snapper configurations are set up for snap-pac's pacman hooks. By default snap-pac
|
|
||||||
will take snapshots for the root configuration and any other configuration which has
|
|
||||||
SNAPSHOT set to yes in its configuration file. See :doc:`configuration`.
|
|
||||||
|
|
||||||
**After restoring snapshot from snap-pac, the pacman database is locked.**
|
|
||||||
|
|
||||||
The pre/post snaphots are taken while pacman is running, so this is expected. Follow
|
|
||||||
the instructions pacman gives you (*e.g.*, removing the lock file). You can add the
|
|
||||||
database lock file to a snapper filter so that snapper won't consider it when
|
|
||||||
performing snapper diff, snapper status, snapper undochange, etc. See the Filters
|
|
||||||
section in :manpage:`snapper(8)` for more information.
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
# snap-pac example configuration file
|
|
||||||
# see snap-pac(8) for more details
|
|
||||||
|
|
||||||
# Each section corresponds with a snapper configuration. Add additional sections to add
|
|
||||||
# other configurations to be snapshotted. By default, only the root configuration is snapshotted.
|
|
||||||
# Create a section named [DEFAULT] to have a setting apply for all snapper configurations
|
|
||||||
|
|
||||||
## Uncomment to set parameters for snapper configuration named root
|
|
||||||
#[root]
|
|
||||||
|
|
||||||
## How many characters to limit the description for snapper.
|
|
||||||
## Default is 72
|
|
||||||
#desc_limit = 72
|
|
||||||
|
|
||||||
## Whether or not to take snapshots of this snapper configuration
|
|
||||||
## Default is True for root configuration and False for all other configurations
|
|
||||||
#snapshot = True
|
|
||||||
|
|
||||||
## What snapper cleanup algorithm to use
|
|
||||||
## Default is number
|
|
||||||
#cleanup_algorithm = number
|
|
||||||
|
|
||||||
## Uncomment to add "important=yes" to userdata for snapshots referring to these packages
|
|
||||||
## Default is []
|
|
||||||
#important_packages = ["linux", "linux-lts"]
|
|
||||||
|
|
||||||
## Uncomment to add "important=yes" to userdata for snapshots that were created with the following commands
|
|
||||||
## Default is []
|
|
||||||
#important_commands = ["pacman -Syu"]
|
|
||||||
|
|
||||||
## Add custom userdata. Each key-value pair should be an item in the list
|
|
||||||
## Default is []
|
|
||||||
#userdata = ["key=value","foo=bar"]
|
|
||||||
|
|
||||||
## Example for another snapper configuration named "home"
|
|
||||||
# [home]
|
|
||||||
## Default is False
|
|
||||||
# snapshot = True
|
|
||||||
22
grub-config
Executable file
22
grub-config
Executable file
|
|
@ -0,0 +1,22 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# snap-pac
|
||||||
|
# Copyright (C) 2016 James W. Barnett
|
||||||
|
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU General Public License along
|
||||||
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
# Regenerates grub configuration file. Useful with grub-btrfs-git.
|
||||||
|
|
||||||
|
/usr/bin/grub-mkconfig -o /boot/grub/grub.cfg 2> /dev/null
|
||||||
|
|
@ -1,161 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
# Copyright (C) 2021 Wes Barnett
|
|
||||||
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation; either version 2 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
|
|
||||||
# You should have received a copy of the GNU General Public License along
|
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
"""Script for taking snapshots; run from pacman hooks."""
|
|
||||||
|
|
||||||
from argparse import ArgumentParser
|
|
||||||
from configparser import ConfigParser
|
|
||||||
import json
|
|
||||||
import logging
|
|
||||||
from pathlib import Path
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
|
|
||||||
logging.basicConfig(format="%(message)s", level=logging.INFO)
|
|
||||||
|
|
||||||
|
|
||||||
class SnapperCmd:
|
|
||||||
|
|
||||||
def __init__(self, config, cleanup_algorithm, description="", nodbus=False, userdata=""):
|
|
||||||
self.cmd = ["snapper"]
|
|
||||||
if nodbus:
|
|
||||||
self.cmd.append("--no-dbus")
|
|
||||||
self.cmd.extend([
|
|
||||||
f"--config {config} create",
|
|
||||||
f"--cleanup-algorithm {cleanup_algorithm}",
|
|
||||||
"--print-number"
|
|
||||||
])
|
|
||||||
self.cmd.append("--read-write")
|
|
||||||
if description:
|
|
||||||
self.cmd.append(f"--description \"{description}\"")
|
|
||||||
if userdata:
|
|
||||||
self.cmd.append(f"--userdata \"{userdata}\"")
|
|
||||||
|
|
||||||
def __call__(self):
|
|
||||||
return os.popen(self.__str__()).read().rstrip("\n")
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return " ".join(self.cmd)
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigProcessor:
|
|
||||||
|
|
||||||
def __init__(self, ini_file, parent_cmd=None, packages=None):
|
|
||||||
"""Set up defaults for snap-pac configuration."""
|
|
||||||
|
|
||||||
if parent_cmd is None:
|
|
||||||
self.parent_cmd = os.popen(f"ps -p {os.getppid()} -o args=").read().strip()
|
|
||||||
else:
|
|
||||||
self.parent_cmd = parent_cmd
|
|
||||||
|
|
||||||
if packages is None:
|
|
||||||
self.packages = [line.rstrip("\n") for line in sys.stdin]
|
|
||||||
else:
|
|
||||||
self.packages = packages
|
|
||||||
|
|
||||||
self.config = ConfigParser()
|
|
||||||
self.config["DEFAULT"] = {
|
|
||||||
"snapshot": False,
|
|
||||||
"cleanup_algorithm": "number",
|
|
||||||
"description": self.parent_cmd,
|
|
||||||
"desc_limit": 72,
|
|
||||||
"important_packages": [],
|
|
||||||
"important_commands": [],
|
|
||||||
"userdata": []
|
|
||||||
}
|
|
||||||
self.config["root"] = {
|
|
||||||
"snapshot": True
|
|
||||||
}
|
|
||||||
self.config.read(ini_file)
|
|
||||||
|
|
||||||
def get_cleanup_algorithm(self, section):
|
|
||||||
return self.config.get(section, "cleanup_algorithm")
|
|
||||||
|
|
||||||
def get_description(self, section):
|
|
||||||
desc_limit = self.config.getint(section, "desc_limit")
|
|
||||||
return self.config.get(section, "description")[:desc_limit]
|
|
||||||
|
|
||||||
def check_important_commands(self, section):
|
|
||||||
return self.parent_cmd in json.loads(self.config.get(section, "important_commands"))
|
|
||||||
|
|
||||||
def check_important_packages(self, section):
|
|
||||||
important_packages = json.loads(self.config.get(section, "important_packages"))
|
|
||||||
return any(x in important_packages for x in self.packages)
|
|
||||||
|
|
||||||
def check_important(self, section):
|
|
||||||
return (self.check_important_commands(section) or
|
|
||||||
self.check_important_packages(section))
|
|
||||||
|
|
||||||
def get_userdata(self, section):
|
|
||||||
userdata = set(json.loads(self.config.get(section, "userdata")))
|
|
||||||
if self.check_important(section):
|
|
||||||
userdata.add("important=yes")
|
|
||||||
return ",".join(sorted(list(userdata)))
|
|
||||||
|
|
||||||
def __call__(self, section):
|
|
||||||
if section not in self.config:
|
|
||||||
self.config.add_section(section)
|
|
||||||
return {
|
|
||||||
"description": self.get_description(section),
|
|
||||||
"cleanup_algorithm": self.get_cleanup_algorithm(section),
|
|
||||||
"userdata": self.get_userdata(section),
|
|
||||||
"snapshot": self.config.getboolean(section, "snapshot")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def get_snapper_configs(conf_file):
|
|
||||||
"""Get the snapper configurations."""
|
|
||||||
for line in conf_file.read_text().split("\n"):
|
|
||||||
if line.startswith("SNAPPER_CONFIGS"):
|
|
||||||
line = line.rstrip("\n").rstrip("\"").split("=")
|
|
||||||
return line[1].lstrip("\"").split()
|
|
||||||
|
|
||||||
|
|
||||||
def check_skip():
|
|
||||||
return os.getenv("SNAP_PAC_SKIP", "n").lower() in ["y", "yes", "true", "1"]
|
|
||||||
|
|
||||||
|
|
||||||
def parse_args():
|
|
||||||
parser = ArgumentParser(description="Script for taking snapper snapshots. Used with pacman hooks.")
|
|
||||||
parser.add_argument(
|
|
||||||
"--ini", dest="snap_pac_ini", type=Path,
|
|
||||||
default=Path("/etc/snap-pac.ini"), help="snap-pac ini file path"
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--conf", dest="snapper_conf_file", type=Path,
|
|
||||||
default=Path("/etc/conf.d/snapper"), help="snapper configuration file path"
|
|
||||||
)
|
|
||||||
return parser.parse_args()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
|
|
||||||
if check_skip():
|
|
||||||
logging.warning("snapper snapshots skipped")
|
|
||||||
quit()
|
|
||||||
|
|
||||||
args = parse_args()
|
|
||||||
config_processor = ConfigProcessor(args.snap_pac_ini)
|
|
||||||
chroot = os.stat("/") != os.stat("/proc/1/root/.")
|
|
||||||
|
|
||||||
for snapper_config in get_snapper_configs(args.snapper_conf_file):
|
|
||||||
|
|
||||||
data = config_processor(snapper_config)
|
|
||||||
if data["snapshot"]:
|
|
||||||
num = SnapperCmd(snapper_config, data["cleanup_algorithm"], data["description"], chroot, data["userdata"])()
|
|
||||||
logging.info(f"==> {snapper_config}: {num}")
|
|
||||||
30
snapper-post
Executable file
30
snapper-post
Executable file
|
|
@ -0,0 +1,30 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# snap-pac
|
||||||
|
# Copyright (C) 2016 James W. Barnett
|
||||||
|
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU General Public License along
|
||||||
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
# Takes a snapper post snapshot after a pacman transaction
|
||||||
|
|
||||||
|
PACMAN_CMD=$(ps -C pacman -o args=)
|
||||||
|
PREFILE=/usr/share/libalpm/hooks.bin/snap-pac/.pre
|
||||||
|
if [ -f $PREFILE ]; then
|
||||||
|
SNAPPERPACPRE=$(cat $PREFILE)
|
||||||
|
snapper --config root create --cleanup-algorithm number --type post --pre-number $SNAPPERPACPRE --description "$PACMAN_CMD"
|
||||||
|
rm $PREFILE
|
||||||
|
else
|
||||||
|
echo "WARNING: $PREFILE does not exist, so not performing post snapshot. If you are initially installing snap-pac, this is normal."
|
||||||
|
fi
|
||||||
24
snapper-pre
Executable file
24
snapper-pre
Executable file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# snap-pac
|
||||||
|
# Copyright (C) 2016 James W. Barnett
|
||||||
|
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU General Public License along
|
||||||
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
# Takes a snapper pre snapshot before a pacman transaction
|
||||||
|
|
||||||
|
PACMAN_CMD=$(ps -C pacman -o args=)
|
||||||
|
PREFILE=/usr/share/libalpm/hooks.bin/snap-pac/.pre
|
||||||
|
snapper --config root create --type pre --cleanup-algorithm number --print-number --description "$PACMAN_CMD" > $PREFILE
|
||||||
|
|
@ -1,122 +0,0 @@
|
||||||
import tempfile
|
|
||||||
from pathlib import Path
|
|
||||||
import os
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
from scripts.snap_pac import check_skip, ConfigProcessor, get_snapper_configs, Prefile, SnapperCmd
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("snapper_cmd, actual_cmd", [
|
|
||||||
(
|
|
||||||
SnapperCmd("root", "pre", "number", "foo"),
|
|
||||||
"snapper --config root create --cleanup-algorithm number --print-number --description \"foo\" --type pre"
|
|
||||||
),
|
|
||||||
(
|
|
||||||
SnapperCmd("root", "post", "number", "bar", False, 1234),
|
|
||||||
"snapper --config root create --cleanup-algorithm number --print-number"
|
|
||||||
" --description \"bar\" --pre-number 1234 --type post"
|
|
||||||
),
|
|
||||||
(
|
|
||||||
SnapperCmd("root", "post", "number", "bar", True, 1234),
|
|
||||||
"snapper --no-dbus --config root create --cleanup-algorithm number --print-number"
|
|
||||||
" --description \"bar\" --pre-number 1234 --type post"
|
|
||||||
),
|
|
||||||
(
|
|
||||||
SnapperCmd("root", "post", "number", "bar", False, 1234, "important=yes"),
|
|
||||||
"snapper --config root create --cleanup-algorithm number --print-number"
|
|
||||||
" --description \"bar\" --userdata \"important=yes\" --pre-number 1234 --type post"
|
|
||||||
),
|
|
||||||
(
|
|
||||||
SnapperCmd("root", "post", "number", "bar", False, 1234, "foo=bar,important=yes"),
|
|
||||||
"snapper --config root create --cleanup-algorithm number --print-number"
|
|
||||||
" --description \"bar\" --userdata \"foo=bar,important=yes\" --pre-number 1234 --type post"
|
|
||||||
),
|
|
||||||
(
|
|
||||||
SnapperCmd("root", "post", "number", "bar", False, None, "foo=bar,important=yes"),
|
|
||||||
"snapper --config root create --cleanup-algorithm number --print-number"
|
|
||||||
" --description \"bar\" --userdata \"foo=bar,important=yes\" --type single"
|
|
||||||
)
|
|
||||||
])
|
|
||||||
def test_snapper_cmd(snapper_cmd, actual_cmd):
|
|
||||||
assert str(snapper_cmd) == actual_cmd
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_snapper_configs():
|
|
||||||
with tempfile.NamedTemporaryFile("w", delete=False) as f:
|
|
||||||
f.write("## Path: System/Snapper\n")
|
|
||||||
f.write("\n")
|
|
||||||
f.write("## Type: string\n")
|
|
||||||
f.write("## Default: \"\"\n")
|
|
||||||
f.write("# List of snapper configurations.\n")
|
|
||||||
f.write("SNAPPER_CONFIGS=\"home root foo bar\"\n")
|
|
||||||
name = f.name
|
|
||||||
assert get_snapper_configs(Path(name)) == ["home", "root", "foo", "bar"]
|
|
||||||
|
|
||||||
|
|
||||||
def test_skip_snap_pac():
|
|
||||||
os.environ["SNAP_PAC_SKIP"] = "y"
|
|
||||||
assert check_skip() is True
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("section, command, packages, snapshot_type, result", [
|
|
||||||
(
|
|
||||||
"root", "foo", ["bar"], "pre",
|
|
||||||
{"description": "foo", "cleanup_algorithm": "number", "userdata": "", "snapshot": True}
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"root", "pacman -Syu", [], "pre",
|
|
||||||
{"description": "pacman -Syu", "cleanup_algorithm": "number", "userdata": "important=yes", "snapshot": True}
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"mail", "pacman -Syu", [], "pre",
|
|
||||||
{"description": "pacman -Syu", "cleanup_algorithm": "number", "userdata": "", "snapshot": False}
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"home", "pacman -Syu", [], "pre",
|
|
||||||
{"description": "pac", "cleanup_algorithm": "number", "userdata": "foo=bar,requestid=42", "snapshot": True}
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"home", "pacman -Syu", [], "post",
|
|
||||||
{"description": "a r", "cleanup_algorithm": "number", "userdata": "foo=bar,requestid=42", "snapshot": True}
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"myconfig", "pacman -S linux", ["linux"], "post",
|
|
||||||
{"description": "linux", "cleanup_algorithm": "timeline",
|
|
||||||
"userdata": "foo=bar,important=yes,requestid=42", "snapshot": True}
|
|
||||||
),
|
|
||||||
])
|
|
||||||
def test_config_processor(section, command, packages, snapshot_type, result):
|
|
||||||
with tempfile.NamedTemporaryFile("w", delete=False) as f:
|
|
||||||
f.write("[root]\n")
|
|
||||||
f.write("important_commands = [\"pacman -Syu\"]\n\n")
|
|
||||||
f.write("[home]\n")
|
|
||||||
f.write("snapshot = True\n")
|
|
||||||
f.write("desc_limit = 3\n")
|
|
||||||
f.write("post_description = a really long description\n")
|
|
||||||
f.write("userdata = [\"foo=bar\", \"requestid=42\"]\n\n")
|
|
||||||
f.write("[myconfig]\n")
|
|
||||||
f.write("snapshot = True\n")
|
|
||||||
f.write("cleanup_algorithm = timeline\n")
|
|
||||||
f.write("important_packages = [\"linux\", \"linux-lts\"]\n")
|
|
||||||
f.write("userdata = [\"foo=bar\", \"requestid=42\"]\n")
|
|
||||||
name = f.name
|
|
||||||
config_processor = ConfigProcessor(name, snapshot_type, command, packages)
|
|
||||||
assert config_processor(section) == result
|
|
||||||
|
|
||||||
|
|
||||||
def test_prefile_read_none():
|
|
||||||
prefile = Prefile("root", "pre")
|
|
||||||
assert prefile.read() is None
|
|
||||||
|
|
||||||
|
|
||||||
def test_prefile_read():
|
|
||||||
prefile = Prefile("root", "pre")
|
|
||||||
prefile.write("1234")
|
|
||||||
prefile = Prefile("root", "post")
|
|
||||||
assert prefile.read() == "1234"
|
|
||||||
|
|
||||||
|
|
||||||
def test_no_prefile():
|
|
||||||
prefile = Prefile("foo-pre-file-not-found", "post")
|
|
||||||
assert prefile.read() is None
|
|
||||||
Loading…
Add table
Reference in a new issue