Skip to content

Commit

Permalink
Initial release
Browse files Browse the repository at this point in the history
* Initial setup
* Setup for pip
  • Loading branch information
bbtufty committed Oct 1, 2024
1 parent 2010f08 commit 18be71f
Show file tree
Hide file tree
Showing 16 changed files with 626 additions and 3 deletions.
44 changes: 44 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Bug report
description: Submit a bug report
title: '[BUG]: '
labels: ['bug']
assignees: 'bbtufty'

body:
- type: textarea
id: description
attributes:
label: Describe the Bug
description: A clear and concise description of the bug.
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected Behavior
description: A clear and concise description of what you expected to happen.
- type: textarea
id: reproduce
attributes:
label: Steps to reproduce the behavior
description: If not present under all circumstances, give a step-by-step on how to reproduce the bug.
value: |
1.
2.
...
- type: textarea
id: screenshots
attributes:
label: Screenshots
description: Attach any applicable screenshots that illustrate your problem.
- type: textarea
id: preferences
attributes:
label: Preference File
description: Paste your config file (likely config.yml), with any sensitive info redacted
render: yaml
- type: textarea
id: log
attributes:
label: Log
description: Attach the relevant log file(s)
33 changes: 33 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Feature
description: Suggest a new feature for this project
title: '[FEAT]: '
labels: ['feature']
assignees: 'bbtufty'

body:
- type: textarea
id: problem
attributes:
label: Problem
description: Is your feature request related to a problem? Please describe
placeholder: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
- type: textarea
id: solution
attributes:
label: Solution
description: Describe the solution you'd like
placeholder: A clear and concise description of what you want to happen.
- type: textarea
id: alternatives
attributes:
label: Alternatives
description: Describe alternatives you've considered
placeholder: A clear and concise description of any alternative solutions or features you've considered.
- type: textarea
id: context
attributes:
label: Context
description: Additional context
placeholder: Add any other context or screenshots about the feature request here.


35 changes: 35 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Build

on:
push:
branches:
- '*'
pull_request:
branches:
- master

jobs:
build_sdist_and_wheel:
name: Build source distribution
runs-on: ubuntu-latest
strategy:
matrix:
# Versions listed at https://raw.githubusercontent.com/actions/python-versions/main/versions-manifest.json
python-version: [
"3.11",
"3.12",
]
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Setup Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install build
- name: Build package
run: python -m build
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -159,4 +159,4 @@ cython_debug/
# 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/
.idea/
30 changes: 30 additions & 0 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details

# Required
version: 2

build:
os: ubuntu-22.04
tools:
python: "3.11"

# Build documentation in the docs/ directory with Sphinx
sphinx:
builder: html
configuration: docs/conf.py
fail_on_warning: true

# Optionally build your docs in additional formats such as PDF and ePub
formats:
- htmlzip
- pdf

# Optionally set the version of Python and requirements required to build your docs
python:
install:
- method: pip
path: .
extra_requirements:
- docs
4 changes: 4 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
0.0.1 (Unreleased)
==================

- Initial release
17 changes: 17 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
include README.md
include CHANGES.rst
include LICENSE
include pyproject.toml

recursive-include *.pyx *.c *.pxd
recursive-include docs *
recursive-include licenses *
recursive-include cextern *
recursive-include scripts *

prune build
prune docs/_build
prune docs/api
prune */__pycache__

global-exclude *.pyc *.o
39 changes: 37 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,37 @@
# nxbrew-watcher
Watch and alert for updates on nxbrew
# NXBrew-watcher

[![Actions](https://img.shields.io/github/actions/workflow/status/bbtufty/nxbrew-watcher/build.yaml?branch=main&style=flat-square)](https://github.com/bbtufty/nxbrew-watcher/actions)
[![License](https://img.shields.io/badge/license-GNUv3-blue.svg?label=License&style=flat-square)](LICENSE)

Intro text

Installation
------------

NXBrew-watcher can be installed by cloning the repository and installing via pip:

```shell
git clone https://github.com/bbtufty/nxbrew-watcher.git
cd nxbrew-watcher
pip install -e .
```

Running NXBrew-watcher
----------------------

After installing, you can run simply by:

```python
import os
os.system(r"python nxbrew-watcher\nxbrew_watcher.py")
```

Environment variables
---------------------

NXBrew-watcher pulls in a number of environment variables that can be configured. These are:

* `CONFIG_DIR`: Where to save cache and log files to
* `NXBREW_DISCORD_URL`: Webhook URL for Discord to post updates (see [here](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks))
* `NXBREW_CADENCE`: Cadence to perform search on (in minutes). Defaults to 1.
* `NXBREW_LOG_LEVEL`: Level for log files. Defaults to INFO
4 changes: 4 additions & 0 deletions nxbrew_watcher.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from nxbrew_watcher import NXBrewWatcher

nxbw = NXBrewWatcher()
nxbw.run()
10 changes: 10 additions & 0 deletions nxbrew_watcher/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from importlib.metadata import version

# Get the version
__version__ = version(__name__)

from .watcher import NXBrewWatcher

__all__ = [
"NXBrewWatcher",
]
10 changes: 10 additions & 0 deletions nxbrew_watcher/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from .discord import discord_push
from .io import load_json, save_json
from .logger import setup_logger

__all__ = [
"setup_logger",
"load_json",
"save_json",
"discord_push",
]
15 changes: 15 additions & 0 deletions nxbrew_watcher/utils/discord.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from discordwebhook import Discord


def discord_push(
url,
embeds,
):
"""Post a message to Discord"""

discord = Discord(url=url)
discord.post(
embeds=embeds,
)

return True
22 changes: 22 additions & 0 deletions nxbrew_watcher/utils/io.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import json


def load_json(file):
"""Load json file"""

with open(file, "r", encoding="utf-8") as f:
j = json.load(f)

return j


def save_json(data, out_file):
"""Save json in a pretty way"""

with open(out_file, "w", encoding="utf-8") as f:
json.dump(
data,
f,
ensure_ascii=False,
indent=4,
)
109 changes: 109 additions & 0 deletions nxbrew_watcher/utils/logger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import logging
import os
import sys
from logging.handlers import RotatingFileHandler

import colorlog
from pathvalidate import sanitize_filename


def setup_logger(
log_level,
script_name,
log_dir,
additional_dir="",
max_logs=9,
):
"""
Set up the logger.
Parameters:
log_level (str): The log level to use
script_name (str): The name of the script
log_dir (str): The directory to save logs to
additional_dir (str): Any additional directories to keep log files tidy
max_logs (int): Maximum number of log files to keep
Returns:
A logger object for logging messages.
"""

# Sanitize the directories if we need to
additional_dir = [sanitize_filename(f) for f in additional_dir.split(os.path.sep)]

if os.environ.get("DOCKER_ENV"):
log_dir = os.path.join(log_dir, script_name, *additional_dir)
else:
log_dir = os.path.join(log_dir, script_name, *additional_dir)

if log_level not in ["DEBUG", "INFO", "CRITICAL"]:
log_level = "INFO"
print(f"Invalid log level '{log_level}', defaulting to 'INFO'")

# Create the log directory if it doesn't exist
if not os.path.exists(log_dir):
os.makedirs(log_dir)

# Define the log file path, and sanitize if needs be
log_file = os.path.join(log_dir, f"{script_name}.log")

# Check if log file already exists
if os.path.isfile(log_file):
for i in range(max_logs - 1, 0, -1):
old_log = f"{log_dir}/{script_name}.log.{i}"
new_log = f"{log_dir}/{script_name}.log.{i + 1}"
if os.path.exists(old_log):
if os.path.exists(new_log):
os.remove(new_log)
os.rename(old_log, new_log)
os.rename(log_file, os.path.join(log_dir, f"{script_name}.log.1"))

# Create a logger object with the script name
logger = logging.getLogger(script_name)
logger.propagate = False

# Set the log level based on the provided parameter
log_level = log_level.upper()
if log_level == "DEBUG":
logger.setLevel(logging.DEBUG)
elif log_level == "INFO":
logger.setLevel(logging.INFO)
elif log_level == "CRITICAL":
logger.setLevel(logging.CRITICAL)
else:
logger.critical(f"Invalid log level '{log_level}', defaulting to 'INFO'")
logger.setLevel(logging.INFO)

# Define the log message format for the log files
logfile_formatter = logging.Formatter(
fmt="%(asctime)s %(levelname)s: %(message)s", datefmt="%m/%d/%y %I:%M %p"
)

# Create a RotatingFileHandler for log files
handler = RotatingFileHandler(log_file, delay=True, mode="w", backupCount=max_logs)
handler.setFormatter(logfile_formatter)

# Add the file handler to the logger
logger.addHandler(handler)

# Configure console logging with the specified log level
console_handler = colorlog.StreamHandler(sys.stdout)
if log_level == "DEBUG":
console_handler.setLevel(logging.DEBUG)
elif log_level == "INFO":
console_handler.setLevel(logging.INFO)
elif log_level == "CRITICAL":
console_handler.setLevel(logging.CRITICAL)

# Add the console handler to the logger
console_handler.setFormatter(
colorlog.ColoredFormatter("%(log_color)s%(levelname)s: %(message)s")
)
logger.addHandler(console_handler)

# Overwrite previous logger if exists
logging.getLogger(script_name).handlers.clear()
logging.getLogger(script_name).addHandler(handler)
logging.getLogger(script_name).addHandler(console_handler)

return logger
Loading

0 comments on commit 18be71f

Please sign in to comment.