Initial commit
This commit is contained in:
commit
558b00793e
163
.gitignore
vendored
Normal file
163
.gitignore
vendored
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py,cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
cover/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
.pybuilder/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
# For a library or package, you might want to ignore these files since the code is
|
||||||
|
# intended to run in multiple environments; otherwise, check them in:
|
||||||
|
# .python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
#Pipfile.lock
|
||||||
|
|
||||||
|
# poetry
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||||
|
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||||
|
# commonly ignored for libraries.
|
||||||
|
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||||
|
#poetry.lock
|
||||||
|
|
||||||
|
# pdm
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||||
|
#pdm.lock
|
||||||
|
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||||
|
# in version control.
|
||||||
|
# https://pdm.fming.dev/#use-with-ide
|
||||||
|
.pdm.toml
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||||
|
__pypackages__/
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
# pytype static type analyzer
|
||||||
|
.pytype/
|
||||||
|
|
||||||
|
# Cython debug symbols
|
||||||
|
cython_debug/
|
||||||
|
|
||||||
|
# PyCharm
|
||||||
|
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||||
|
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||||
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
|
#.idea/
|
||||||
|
|
||||||
|
# Application
|
||||||
|
config.ini
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 niku
|
||||||
|
|
||||||
|
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.
|
16
README.md
Normal file
16
README.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# contrib-scribe
|
||||||
|
Your contribution heatmap is a canvas for creativity.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
- systemd
|
||||||
|
- python (>=3.10)
|
||||||
|
- git
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
```sh
|
||||||
|
# Start
|
||||||
|
./scripts/install.sh
|
||||||
|
|
||||||
|
# Stop
|
||||||
|
./scripts/uninstall.sh
|
||||||
|
```
|
4
config.ini.sample
Normal file
4
config.ini.sample
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[contrib_scribe]
|
||||||
|
repo_path = ~/path/to/repo
|
||||||
|
message = hi there
|
||||||
|
commit_count = 3
|
342
contrib_scribe.py
Executable file
342
contrib_scribe.py
Executable file
@ -0,0 +1,342 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import base64
|
||||||
|
import configparser
|
||||||
|
import typing
|
||||||
|
import sys
|
||||||
|
import pathlib
|
||||||
|
from datetime import date, timedelta
|
||||||
|
import subprocess as sub
|
||||||
|
import appdirs
|
||||||
|
|
||||||
|
CharRepr = typing.List[typing.List[typing.Literal[0] | typing.Literal[1]]]
|
||||||
|
|
||||||
|
CHAR_SPACING = 1
|
||||||
|
FONT_MAP: typing.Mapping[str, CharRepr] = {
|
||||||
|
"A": [
|
||||||
|
[0, 1, 1, 0],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 1, 1, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
],
|
||||||
|
"B": [
|
||||||
|
[1, 1, 1, 0],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 1, 1, 0],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 1, 1, 0],
|
||||||
|
],
|
||||||
|
"C": [
|
||||||
|
[0, 1, 1, 0],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 0],
|
||||||
|
[1, 0, 0, 0],
|
||||||
|
[1, 0, 0, 0],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[0, 1, 1, 0],
|
||||||
|
],
|
||||||
|
"D": [
|
||||||
|
[1, 1, 1, 0],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 1, 1, 0],
|
||||||
|
],
|
||||||
|
"E": [
|
||||||
|
[1, 1, 1],
|
||||||
|
[1, 0, 0],
|
||||||
|
[1, 0, 0],
|
||||||
|
[1, 1, 1],
|
||||||
|
[1, 0, 0],
|
||||||
|
[1, 0, 0],
|
||||||
|
[1, 1, 1],
|
||||||
|
],
|
||||||
|
"F": [
|
||||||
|
[1, 1, 1, 1],
|
||||||
|
[1, 0, 0, 0],
|
||||||
|
[1, 0, 0, 0],
|
||||||
|
[1, 1, 1, 1],
|
||||||
|
[1, 0, 0, 0],
|
||||||
|
[1, 0, 0, 0],
|
||||||
|
[1, 0, 0, 0],
|
||||||
|
],
|
||||||
|
"G": [
|
||||||
|
[0, 1, 1, 0],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 0],
|
||||||
|
[1, 0, 1, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[0, 1, 1, 1],
|
||||||
|
],
|
||||||
|
"H": [
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 1, 1, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
],
|
||||||
|
"I": [
|
||||||
|
[1],
|
||||||
|
[1],
|
||||||
|
[1],
|
||||||
|
[1],
|
||||||
|
[1],
|
||||||
|
[1],
|
||||||
|
[1],
|
||||||
|
],
|
||||||
|
"J": [
|
||||||
|
[0, 0, 1],
|
||||||
|
[0, 0, 1],
|
||||||
|
[0, 0, 1],
|
||||||
|
[0, 0, 1],
|
||||||
|
[0, 0, 1],
|
||||||
|
[1, 0, 1],
|
||||||
|
[1, 1, 1],
|
||||||
|
],
|
||||||
|
"K": [
|
||||||
|
[1, 0, 1],
|
||||||
|
[1, 0, 1],
|
||||||
|
[1, 0, 1],
|
||||||
|
[1, 1, 0],
|
||||||
|
[1, 0, 1],
|
||||||
|
[1, 0, 1],
|
||||||
|
[1, 0, 1],
|
||||||
|
],
|
||||||
|
"L": [
|
||||||
|
[1, 0, 0],
|
||||||
|
[1, 0, 0],
|
||||||
|
[1, 0, 0],
|
||||||
|
[1, 0, 0],
|
||||||
|
[1, 0, 0],
|
||||||
|
[1, 0, 0],
|
||||||
|
[1, 1, 1],
|
||||||
|
],
|
||||||
|
"M": [
|
||||||
|
[0, 1, 0, 1, 0],
|
||||||
|
[1, 0, 1, 0, 1],
|
||||||
|
[1, 0, 1, 0, 1],
|
||||||
|
[1, 0, 1, 0, 1],
|
||||||
|
[1, 0, 1, 0, 1],
|
||||||
|
[1, 0, 1, 0, 1],
|
||||||
|
[1, 0, 1, 0, 1],
|
||||||
|
],
|
||||||
|
"N": [
|
||||||
|
[1, 1, 0, 0, 1],
|
||||||
|
[1, 1, 0, 0, 1],
|
||||||
|
[1, 0, 1, 0, 1],
|
||||||
|
[1, 0, 1, 0, 1],
|
||||||
|
[1, 0, 1, 0, 1],
|
||||||
|
[1, 0, 0, 1, 1],
|
||||||
|
[1, 0, 0, 1, 1],
|
||||||
|
],
|
||||||
|
"O": [
|
||||||
|
[0, 1, 1, 0],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[0, 1, 1, 0],
|
||||||
|
],
|
||||||
|
"P": [
|
||||||
|
[1, 1, 1, 0],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 1, 1, 0],
|
||||||
|
[1, 0, 0, 0],
|
||||||
|
[1, 0, 0, 0],
|
||||||
|
[1, 0, 0, 0],
|
||||||
|
],
|
||||||
|
"Q": [
|
||||||
|
[0, 1, 1, 0],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 1, 1],
|
||||||
|
[0, 1, 1, 1],
|
||||||
|
],
|
||||||
|
"R": [
|
||||||
|
[0, 1, 1, 0],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 1, 1, 0],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
],
|
||||||
|
"S": [
|
||||||
|
[0, 1, 1, 0],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[1, 0, 0, 0],
|
||||||
|
[0, 1, 1, 0],
|
||||||
|
[0, 0, 0, 1],
|
||||||
|
[1, 0, 0, 1],
|
||||||
|
[0, 1, 1, 0],
|
||||||
|
],
|
||||||
|
"T": [
|
||||||
|
[1, 1, 1],
|
||||||
|
[0, 1, 0],
|
||||||
|
[0, 1, 0],
|
||||||
|
[0, 1, 0],
|
||||||
|
[0, 1, 0],
|
||||||
|
[0, 1, 0],
|
||||||
|
[0, 1, 0],
|
||||||
|
],
|
||||||
|
"U": [
|
||||||
|
[1, 0, 1],
|
||||||
|
[1, 0, 1],
|
||||||
|
[1, 0, 1],
|
||||||
|
[1, 0, 1],
|
||||||
|
[1, 0, 1],
|
||||||
|
[1, 0, 1],
|
||||||
|
[1, 1, 1],
|
||||||
|
],
|
||||||
|
"V": [
|
||||||
|
[1, 0, 1],
|
||||||
|
[1, 0, 1],
|
||||||
|
[1, 0, 1],
|
||||||
|
[1, 0, 1],
|
||||||
|
[1, 0, 1],
|
||||||
|
[1, 0, 1],
|
||||||
|
[0, 1, 0],
|
||||||
|
],
|
||||||
|
"W": [
|
||||||
|
[1, 0, 1, 0, 1],
|
||||||
|
[1, 0, 1, 0, 1],
|
||||||
|
[1, 0, 1, 0, 1],
|
||||||
|
[1, 0, 1, 0, 1],
|
||||||
|
[1, 0, 1, 0, 1],
|
||||||
|
[1, 0, 1, 0, 1],
|
||||||
|
[0, 1, 0, 1, 0],
|
||||||
|
],
|
||||||
|
"X": [
|
||||||
|
[1, 0, 1],
|
||||||
|
[1, 0, 1],
|
||||||
|
[1, 0, 1],
|
||||||
|
[0, 1, 0],
|
||||||
|
[1, 0, 1],
|
||||||
|
[1, 0, 1],
|
||||||
|
[1, 0, 1],
|
||||||
|
],
|
||||||
|
"Y": [
|
||||||
|
[1, 0, 1],
|
||||||
|
[1, 0, 1],
|
||||||
|
[1, 0, 1],
|
||||||
|
[1, 1, 1],
|
||||||
|
[0, 0, 1],
|
||||||
|
[0, 0, 1],
|
||||||
|
[1, 1, 1],
|
||||||
|
],
|
||||||
|
"Z": [
|
||||||
|
[1, 1, 1, 1],
|
||||||
|
[0, 0, 0, 1],
|
||||||
|
[0, 0, 1, 0],
|
||||||
|
[0, 1, 0, 0],
|
||||||
|
[0, 1, 0, 0],
|
||||||
|
[1, 0, 0, 0],
|
||||||
|
[1, 1, 1, 1],
|
||||||
|
],
|
||||||
|
" ": [
|
||||||
|
[0, 0],
|
||||||
|
[0, 0],
|
||||||
|
[0, 0],
|
||||||
|
[0, 0],
|
||||||
|
[0, 0],
|
||||||
|
[0, 0],
|
||||||
|
[0, 0],
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def message_to_matrix(message: str) -> CharRepr:
|
||||||
|
matrix: CharRepr = [[] for _ in range(7)]
|
||||||
|
|
||||||
|
for char in message:
|
||||||
|
crepr = FONT_MAP.get(char)
|
||||||
|
if not crepr:
|
||||||
|
raise ValueError(f'No repr for "{char}" found in font mapping.')
|
||||||
|
for i in range(7):
|
||||||
|
matrix[i].extend(crepr[i])
|
||||||
|
matrix[i].extend([0] * CHAR_SPACING)
|
||||||
|
|
||||||
|
return matrix
|
||||||
|
|
||||||
|
|
||||||
|
def print_char_matrix(matrix: CharRepr):
|
||||||
|
fill = {0: " ", 1: "█"}
|
||||||
|
for row in matrix:
|
||||||
|
print("".join(fill[char] for char in row))
|
||||||
|
|
||||||
|
print(f"\nWidth: {len(matrix[0])}")
|
||||||
|
|
||||||
|
|
||||||
|
def parse_config(path: str) -> typing.Mapping[str, str]:
|
||||||
|
parser = configparser.ConfigParser()
|
||||||
|
parser.read(path)
|
||||||
|
return parser["contrib_scribe"]
|
||||||
|
|
||||||
|
|
||||||
|
def parse_state(path: pathlib.Path) -> date:
|
||||||
|
if not path.exists():
|
||||||
|
state = date.today()
|
||||||
|
if (weekday := state.weekday()) != 6:
|
||||||
|
state += timedelta(days=6 - weekday)
|
||||||
|
with path.open("w") as fp:
|
||||||
|
fp.write(str(state))
|
||||||
|
return state
|
||||||
|
|
||||||
|
with path.open("r") as fp:
|
||||||
|
return date.fromisoformat(fp.read())
|
||||||
|
|
||||||
|
|
||||||
|
def main(args: typing.Sequence[str]) -> int:
|
||||||
|
if len(args) < 1:
|
||||||
|
print("Usage: contrib_scribe.py <config.ini>", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
cfg = parse_config(args[0])
|
||||||
|
cfg_id = base64.b32encode(bytearray(args[0], "ascii")).decode("utf-8")
|
||||||
|
|
||||||
|
data_dir = appdirs.user_data_dir("contrib-scribe")
|
||||||
|
data_path = pathlib.Path(data_dir)
|
||||||
|
data_path.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
state_path = data_path / cfg_id
|
||||||
|
start_date = parse_state(state_path)
|
||||||
|
|
||||||
|
message = cfg["message"].upper()
|
||||||
|
matrix = message_to_matrix(message)
|
||||||
|
|
||||||
|
print_char_matrix(matrix)
|
||||||
|
|
||||||
|
day_diff = (date.today() - start_date).days
|
||||||
|
row, column = day_diff % 7, day_diff // 7
|
||||||
|
if matrix[row][column] == 0:
|
||||||
|
print("No commit's to do today!")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
file_path = pathlib.Path(cfg["repo_path"]) / "test"
|
||||||
|
commit_count = int(cfg["commit_count"])
|
||||||
|
for i in range(commit_count):
|
||||||
|
file_path.write_text(str(i))
|
||||||
|
commands = [["git", "add", "."], ["git", "commit", "-m", str(i)]]
|
||||||
|
for command in commands:
|
||||||
|
sub.call(command, cwd=file_path.parent)
|
||||||
|
|
||||||
|
sub.call(["git", "push"], cwd=file_path.parent)
|
||||||
|
print("Did daily commit")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main(sys.argv[1:]))
|
6
contrib_scribe_test.py
Normal file
6
contrib_scribe_test.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import contrib_scribe
|
||||||
|
|
||||||
|
|
||||||
|
def test_font_size():
|
||||||
|
for char, crepr in contrib_scribe.FONT.items():
|
||||||
|
assert len(crepr) == 7, f'"{char}" is taller than 7 pixels'
|
1
requirements-dev.txt
Normal file
1
requirements-dev.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
pytest
|
1
requirements.txt
Normal file
1
requirements.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
appdirs
|
26
scripts/install.sh
Normal file
26
scripts/install.sh
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Sets up the necessary systemd timer & service.
|
||||||
|
|
||||||
|
service_name=contrib-writer
|
||||||
|
|
||||||
|
sudo tee /usr/lib/systemd/user/$service_name.service &>/dev/null <<EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Your contribution heatmap is a canvas for creativity.
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=$(pwd)/contrib_scribe.py $(pwd)/config.ini
|
||||||
|
EOF
|
||||||
|
|
||||||
|
sudo tee /usr/lib/systemd/user/$service_name.timer &>/dev/null <<EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Your contribution heatmap is a canvas for creativity.
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnCalendar=daily
|
||||||
|
Persistent=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
systemctl enable --user contrib-writer.timer --now
|
10
scripts/uninstall.sh
Executable file
10
scripts/uninstall.sh
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Deletes related created systemd timer & service.
|
||||||
|
|
||||||
|
service_name=contrib-writer
|
||||||
|
|
||||||
|
systemctl disable --user $service_name.timer
|
||||||
|
systemctl stop --user $service_name.timer
|
||||||
|
|
||||||
|
sudo rm /usr/lib/systemd/user/$service_name.service
|
||||||
|
sudo rm /usr/lib/systemd/user/$service_name.timer
|
Loading…
x
Reference in New Issue
Block a user