commit
979744edd5
8 changed files with 137 additions and 13 deletions
2
bin/nur
2
bin/nur
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -p python3 -p nix-prefetch-git -p nix -i python3
|
||||
#!nix-shell -p python3 -p python3.pkgs.irc -p nix-prefetch-git -p nix -i python3
|
||||
import sys
|
||||
import os
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,8 @@ git config --global commit.gpgsign true
|
|||
|
||||
git clone git@github.com:nix-community/nur-combined
|
||||
|
||||
result/bin/nur combine nur-combined
|
||||
result/bin/nur combine \
|
||||
--irc-notify nur-bot@chat.freenode.net:6697/nixos-nur nur-combined
|
||||
|
||||
if [[ -z "$(git diff --exit-code)" ]]; then
|
||||
echo "No changes to the output on this push; exiting."
|
||||
|
|
|
|||
|
|
@ -18,6 +18,11 @@ def parse_arguments(argv: List[str]) -> argparse.Namespace:
|
|||
subparsers = parser.add_subparsers(description="subcommands")
|
||||
|
||||
combine = subparsers.add_parser("combine")
|
||||
combine.add_argument(
|
||||
"--irc-notify",
|
||||
type=str,
|
||||
help="Example nur-bot@chat.freenode.net:6697/nixos-nur",
|
||||
)
|
||||
combine.add_argument("directory")
|
||||
combine.set_defaults(func=combine_command)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ import logging
|
|||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
from tempfile import TemporaryDirectory
|
||||
from argparse import Namespace
|
||||
from distutils.dir_util import copy_tree
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional
|
||||
from tempfile import TemporaryDirectory
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
from .fileutils import chdir, write_json_file
|
||||
from .manifest import Repo, load_manifest, update_lock_file
|
||||
|
|
@ -65,28 +65,39 @@ def commit_repo(repo: Repo, message: str, path: Path) -> Repo:
|
|||
return repo
|
||||
|
||||
|
||||
def repo_link(path: Path) -> str:
|
||||
commit = subprocess.check_output(["git", "-C", path, "rev-parse", "HEAD"])
|
||||
rev = commit.decode("utf-8").strip()[:10]
|
||||
return f"https://github.com/nix-community/nur-combined/commit/{rev}"
|
||||
|
||||
|
||||
def update_combined_repo(
|
||||
combined_repo: Optional[Repo], repo: Repo, path: Path
|
||||
) -> Optional[Repo]:
|
||||
) -> Tuple[Optional[Repo], Optional[str]]:
|
||||
if repo.locked_version is None:
|
||||
return None
|
||||
return None, None
|
||||
|
||||
new_rev = repo.locked_version.rev
|
||||
if combined_repo is None:
|
||||
return commit_repo(repo, f"{repo.name}: init at {new_rev}", path)
|
||||
message = f"{repo.name}: init at {new_rev[:10]} ({repo_link(path)})"
|
||||
repo = commit_repo(repo, message, path)
|
||||
message += f" ({repo_link(path)})"
|
||||
return repo, message
|
||||
|
||||
assert combined_repo.locked_version is not None
|
||||
old_rev = combined_repo.locked_version.rev
|
||||
|
||||
if combined_repo.locked_version == repo.locked_version:
|
||||
return repo
|
||||
return repo, None
|
||||
|
||||
if new_rev != old_rev:
|
||||
message = f"{repo.name}: {old_rev} -> {new_rev}"
|
||||
message = f"{repo.name}: {old_rev[:10]} -> {new_rev[:10]}"
|
||||
else:
|
||||
message = f"{repo.name}: update"
|
||||
|
||||
return commit_repo(repo, message, path)
|
||||
repo = commit_repo(repo, message, path)
|
||||
message += f" ({repo_link(path)})"
|
||||
return repo, message
|
||||
|
||||
|
||||
def remove_repo(repo: Repo, path: Path) -> None:
|
||||
|
|
@ -104,7 +115,7 @@ def update_manifest(repos: List[Repo], path: Path) -> None:
|
|||
write_json_file(dict(repos=d), path)
|
||||
|
||||
|
||||
def update_combined(path: Path) -> None:
|
||||
def update_combined(path: Path) -> List[str]:
|
||||
manifest = load_manifest(MANIFEST_PATH, LOCK_PATH)
|
||||
|
||||
combined_repos = load_combined_repos(path)
|
||||
|
|
@ -113,6 +124,7 @@ def update_combined(path: Path) -> None:
|
|||
os.makedirs(repos_path, exist_ok=True)
|
||||
|
||||
updated_repos = []
|
||||
notifications = []
|
||||
|
||||
for repo in manifest.repos:
|
||||
combined_repo = None
|
||||
|
|
@ -120,13 +132,17 @@ def update_combined(path: Path) -> None:
|
|||
combined_repo = combined_repos[repo.name]
|
||||
del combined_repos[repo.name]
|
||||
try:
|
||||
new_repo = update_combined_repo(combined_repo, repo, repos_path)
|
||||
new_repo, notification = update_combined_repo(
|
||||
combined_repo, repo, repos_path
|
||||
)
|
||||
except Exception:
|
||||
logger.exception(f"Failed to updated repository {repo.name}")
|
||||
continue
|
||||
|
||||
if new_repo is not None:
|
||||
updated_repos.append(new_repo)
|
||||
if notification is not None:
|
||||
notifications.append(notification)
|
||||
|
||||
for combined_repo in combined_repos.values():
|
||||
remove_repo(combined_repo, path)
|
||||
|
|
@ -138,6 +154,8 @@ def update_combined(path: Path) -> None:
|
|||
with chdir(path):
|
||||
commit_files(["repos.json", "repos.json.lock"], "update repos.json + lock")
|
||||
|
||||
return notifications
|
||||
|
||||
|
||||
def setup_combined() -> None:
|
||||
manifest_path = "repos.json"
|
||||
|
|
@ -164,4 +182,12 @@ def combine_command(args: Namespace) -> None:
|
|||
|
||||
with chdir(combined_path):
|
||||
setup_combined()
|
||||
update_combined(combined_path)
|
||||
notifications = update_combined(combined_path)
|
||||
|
||||
if args.irc_notify:
|
||||
from .irc_notify import send
|
||||
|
||||
try:
|
||||
send(args.irc_notify, notifications)
|
||||
except Exception as e:
|
||||
print(f"failed to send irc notifications: {e}")
|
||||
|
|
|
|||
86
nur/irc_notify.py
Normal file
86
nur/irc_notify.py
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
import ssl
|
||||
from typing import List, Optional
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from irc.client import Connection, Event, Reactor, ServerConnectionError, is_channel
|
||||
from irc.connection import Factory
|
||||
|
||||
|
||||
class Exit(SystemExit):
|
||||
pass
|
||||
|
||||
|
||||
def send(url: str, notifications: List[str]) -> None:
|
||||
parsed = urlparse(f"http://{url}")
|
||||
username = parsed.username or "nur-bot"
|
||||
server = parsed.hostname or "chat.freenode.de"
|
||||
if parsed.path != "/" or parsed.path == "":
|
||||
channel = f"#{parsed.path[1:]}"
|
||||
else:
|
||||
channel = "#nixos-nur"
|
||||
port = parsed.port or 6697
|
||||
password = parsed.password
|
||||
if len(notifications) == 0:
|
||||
return
|
||||
_send(
|
||||
notifications=notifications,
|
||||
nickname=username,
|
||||
password=password,
|
||||
server=server,
|
||||
channel=channel,
|
||||
port=port,
|
||||
)
|
||||
|
||||
|
||||
class _send:
|
||||
def __init__(
|
||||
self,
|
||||
notifications: List[str],
|
||||
server: str,
|
||||
nickname: str,
|
||||
port: int,
|
||||
channel: str,
|
||||
password: Optional[str] = None,
|
||||
use_ssl: bool = True,
|
||||
) -> None:
|
||||
self.notifications = notifications
|
||||
self.channel = channel
|
||||
|
||||
ssl_factory = None
|
||||
if use_ssl:
|
||||
ssl_factory = Factory(wrapper=ssl.wrap_socket)
|
||||
reactor = Reactor()
|
||||
try:
|
||||
s = reactor.server()
|
||||
c = s.connect(
|
||||
server, port, nickname, password=password, connect_factory=ssl_factory
|
||||
)
|
||||
except ServerConnectionError as e:
|
||||
print(f"error sending irc notification {e}")
|
||||
return
|
||||
|
||||
c.add_global_handler("welcome", self.on_connect)
|
||||
c.add_global_handler("join", self.on_join)
|
||||
c.add_global_handler("disconnect", self.on_disconnect)
|
||||
|
||||
try:
|
||||
reactor.process_forever()
|
||||
except Exit:
|
||||
pass
|
||||
|
||||
def on_connect(self, connection: Connection, event: Event) -> None:
|
||||
if is_channel(self.channel):
|
||||
connection.join(self.channel)
|
||||
return
|
||||
self.main_loop(connection)
|
||||
|
||||
def on_join(self, connection: Connection, event: Event) -> None:
|
||||
self.main_loop(connection)
|
||||
|
||||
def on_disconnect(self, connection: Connection, event: Event) -> None:
|
||||
raise Exit()
|
||||
|
||||
def main_loop(self, connection: Connection) -> None:
|
||||
for notification in self.notifications:
|
||||
connection.privmsg(self.channel, notification)
|
||||
connection.quit("Bye")
|
||||
|
|
@ -6,6 +6,8 @@ python3Packages.buildPythonApplication {
|
|||
name = "nur";
|
||||
src = ./.;
|
||||
|
||||
propagatedBuildInputs = [ python3Packages.irc ];
|
||||
|
||||
makeWrapperArgs = [
|
||||
"--prefix" "PATH" ":" "${stdenv.lib.makeBinPath [ nix-prefetch-git git nix ]}"
|
||||
"--set" "LOCALE_ARCHIVE" "${glibcLocales}/lib/locale/locale-archive"
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@ max-line-length = 88
|
|||
ignore = E501,E741,W503
|
||||
exclude = .git,__pycache__,docs/source/conf.py,old,build,dist
|
||||
|
||||
[mypy-irc.*]
|
||||
ignore_missing_imports = True
|
||||
|
||||
[mypy]
|
||||
warn_redundant_casts = true
|
||||
disallow_untyped_calls = true
|
||||
|
|
|
|||
1
setup.py
1
setup.py
|
|
@ -14,6 +14,7 @@ setup(
|
|||
license="MIT",
|
||||
packages=find_packages(),
|
||||
entry_points={"console_scripts": ["nur = nur:main"]},
|
||||
install_requires=["irc"],
|
||||
extras_require={"dev": ["mypy", "flake8>=3.5,<3.6", "black"]},
|
||||
classifiers=[
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue