{ config, pkgs, ... }: let git-token = config.sops.secrets."github-token".path; update-checker = pkgs.writeScriptBin "update-checker" '' #!/usr/bin/env nix-shell #! nix-shell -i python3 --pure #! nix-shell -p python3 python3Packages.pygithub python3Packages.feedparser python3Packages.requests nix-prefetch-scripts nix import os import json import subprocess from github import Github from github import Auth import feedparser import requests token = None with open('${git-token}', 'r') as token_file: token = token_file.readline() auth = Auth.Token(token) def check_github(owner, repo, version): try: release = None result = None prefetch = None ghub = Github(auth=auth) print(' getting repo ' + owner + '/' + repo) repo = ghub.get_repo(owner + '/' + repo) if '-b' in version: release = repo.get_releases()[0] latest_version = release.name else: try: release = repo.get_latest_release() latest_version = release.tag_name except: tags = repo.get_tags() try: if tags is not None: latest_version = tags[0].name except: commits = repo.get_commits() latest_version = commits[0].sha if latest_version is not None: if latest_version.replace('v',''\'') != version.replace('v',''\''): print(' update found') print(' Current version: ' + version) print(' Latest version: ' + latest_version) result = subprocess.check_output(['nix-prefetch-git', '--quiet', repo.clone_url, '--rev', latest_version]) prefetch = json.loads(result) print(' New hash: ' + prefetch.get('hash')) else: print(' no update') ghub.close() except Exception as e: print(e) def check_codeberg(owner, repo, version): feed = feedparser.parse('https://codeberg.org/{0}/{1}/releases.rss'.format(owner, repo)) if feed.status == 200: entry = feed.entries[0] if entry.title.replace('v',''\'') != version.replace('v',''\''): print(' update found') print(' Current version: ' + version) print(' Latest version: ' + entry.title) sha256 = subprocess.check_output(['nix-prefetch-url', url.replace(''\'''\${version}', entry.title.replace('v', ''\''))]) prefetch = subprocess.check_output(['nix', 'hash', 'convert', '--hash-algo', 'sha256', str(sha256.decode('utf-8').strip())]) print(' New hash: ' + prefetch.decode('utf-8').strip()) else: print(' no update') def check_open_vsx(publisher, name, version): open_vsx = requests.get('https://open-vsx.org/api/' + publisher + '/' + name) if open_vsx.status_code == 200: extension = open_vsx.json() latest_version = extension.get('version') url = extension.get('files').get('download') if latest_version.replace('v',''\'') != version.replace('v',''\''): print(' update found') print(' Current version: ' + version) print(' Latest version: ' + latest_version) sha256 = subprocess.check_output(['nix-prefetch-url', url]) prefetch = subprocess.check_output(['nix', 'hash', 'convert', '--hash-algo', 'sha256', str(sha256.decode('utf-8').strip())]) print(' New hash: ' + prefetch.decode('utf-8').strip()) else: print(' no update') def parse_nix(package_spec): version = None url = None current_hash = None owner = None repo = None pname = None name = None publisher = None for line in package_spec.readlines(): if 'owner = "' in line and owner is None: owner = line.split(' = ')[-1].replace('"', ''\'').replace(';\n', ''\'') if 'repo = "' in line and repo is None: repo = line.split(' = ')[-1].replace('"', ''\'').replace(';\n', ''\'') if 'version = "' in line and version is None: version = line.split(' = ')[-1].replace('"', ''\'').replace(';\n', ''\'') if 'rev = "' in line and ''\'''\${version}' not in line: version = line.split(' = ')[-1].replace('"', ''\'').replace(';\n', ''\'') if 'url = "' in line and url is None: url = line.split(' = ')[-1].replace('"', ''\'').replace(';\n', ''\'') if 'sha256 = "' in line or ' hash = "' in line and current_hash is None: current_hash = line.split(' = ')[-1].replace('"', ''\'').replace(';\n', ''\'') if 'pname = "' in line and pname is None: pname = line.split(' = ')[-1].replace('"', ''\'').replace(';\n', ''\'') if ' name = "' in line and name is None: name = line.split(' = ')[-1].replace('"', ''\'').replace(';\n', ''\'') if 'publisher = "' in line and publisher is None: publisher = line.split(' = ')[-1].replace('"', ''\'').replace(';\n', ''\'') if url is None and repo is not None: if 'pname' in repo: repo = repo.replace(''\'''\${pname}', pname) url = 'https://github.com/{0}/{1}/releases/tag/{2}'.format(owner, repo, version) if url is not None and repo is None and 'github' in url: owner = url.split('github.com/')[-1].split('/')[0] repo = url.split('github.com/')[-1].split('/')[1] if url is not None and repo is None and 'codeberg' in url: owner = url.split('codeberg.org/')[-1].split('/')[0] repo = url.split('codeberg.org/')[-1].split('/')[1] if url is not None and version is None: version = url.split('/')[-1].replace('.tar.gz', ''\'') if url is not None and publisher is not None: url = url.replace(''\'''\${publisher}', publisher).replace(''\'''\${name}', name) return url, current_hash, owner, repo, pname, name, publisher, version def parse_json(json_versions, flavor=''\''): versions = json.load(json_versions) linux_versions = versions.get('linux') config_versions = versions.get('config') patch_versions = versions.get('patches') zfs_versions = versions.get('zfs') check_kernel(linux_versions, flavor) check_cachy_config(config_versions, flavor) check_patch_versions(patch_versions, flavor) check_zfs_versions(zfs_versions, flavor) def check_kernel(linux_versions, flavor=''\''): srcinfo = requests.get('https://raw.githubusercontent.com/CachyOS/linux-cachyos/master/linux-cachyos' + flavor + '/.SRCINFO') for line in srcinfo.text.split('\n'): if 'pkgver = ' in line: kernel_version = line.split('=')[-1].strip() if kernel_version[-2:] == '.0': kernel_version = kernel_version[:-2] if flavor in [''\'', '-lts', '-server', '-gcc', '-hardened']: release_src = 'https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-' + kernel_version + '.tar.xz' if flavor == '-rc': release_src = 'https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/snapshot/linux-' + kernel_version.replace('.rc', '-rc') + '.tar.gz' sha256 = subprocess.check_output(['nix-prefetch-url', release_src]) prefetch = subprocess.check_output(['nix', 'hash', 'convert', '--hash-algo', 'sha256', str(sha256.decode('utf-8').strip())]) current_version = linux_versions.get('version') current_hash = linux_versions.get('hash') latest_hash = prefetch.decode('utf-8').strip() print(' Checking linux versions...') if current_hash != latest_hash: print(' Current rev: ' + current_version) print(' Current hash: ' + current_hash) print(' New rev: ' + kernel_version) print(' New hash: ' + latest_hash) else: print(' no update') def check_cachy_config(config_versions, flavor=''\''): result = subprocess.check_output(['nix-prefetch-git', '--quiet', 'https://github.com/CachyOS/linux-cachyos.git']) prefetch = json.loads(result) current_version = config_versions.get('rev') latest_version = prefetch.get('rev') print(' Checking config versions...') if current_version != latest_version: print(' Current rev: ' + current_version) print(' New rev: ' + latest_version) print(' New hash: ' + prefetch.get('hash')) else: print(' no update') def check_patch_versions(patch_versions, flavor=''\''): result = subprocess.check_output(['nix-prefetch-git', '--quiet', 'https://github.com/CachyOS/kernel-patches.git']) prefetch = json.loads(result) current_version = patch_versions.get('rev') latest_version = prefetch.get('rev') print(' Checking patch versions...') if current_version != latest_version: print(' Current rev: ' + current_version) print(' New rev: ' + latest_version) print(' New hash: ' + prefetch.get('hash')) else: print(' no update') def kconfig_to_nix(flavor=''\''): kconfig_result = subprocess.check_output(['nix', 'build', '.#nixosConfigurations.jallen-nas.pkgs.linuxPackages_cachyos' + flavor + '.kernel.kconfigToNix', '--no-link', '--print-out-paths']) config_file = kconfig_result.decode('utf-8').strip() if flavor == ''\'': cachy_flavor = '-gcc' result = subprocess.check_output(['cat', config_file]) with open('/etc/nixos/packages/linux-cachyos/config-nix/cachyos' + cachy_flavor + '.x86_64-linux.nix', 'w') as config: config.write(result.decode('utf-8').strip()) def check_zfs_versions(zfs_versions, flavor=''\''): result = requests.get('https://raw.githubusercontent.com/CachyOS/linux-cachyos/master/linux-cachyos' + flavor + '/PKGBUILD') for line in result.text.split('\n'): if 'git+https://github.com/cachyos/zfs.git#commit=' in line: zfs_rev = line.split('zfs.git#commit=')[-1].replace('")', ''\'') result = subprocess.check_output(['nix-prefetch-git', '--quiet', 'https://github.com/CachyOS/zfs.git', '--rev', zfs_rev]) prefetch = json.loads(result) current_version = zfs_versions.get('rev') latest_version = prefetch.get('rev') print(' Checking zfs versions...') if current_version != latest_version: print(' Current rev: ' + current_version) print(' New rev: ' + latest_version) print(' New hash: ' + prefetch.get('hash')) else: print(' no update') for (root,dirs,files) in os.walk('/etc/nixos/packages',topdown=True): if 'default.nix' in files and 'versions.json' not in files: print(root.split('/')[-1]) with open(root + '/default.nix', 'r') as package_spec: url, current_hash, owner, repo, pname, name, publisher, version = parse_nix(package_spec) if owner is not None and repo is not None and 'codeberg' in url: check_codeberg(owner, repo, version) elif owner is not None and repo is not None and 'github' in url: check_github(owner, repo, version) elif publisher is not None and 'open-vsx' in url: check_open_vsx(publisher, name, version) else: if url is not None: print(url) if 'default.nix' in files and 'versions.json' in files: with open(root + '/versions.json', 'r') as json_versions: print('Checking Linux CachyOS') parse_json(json_versions) with open(root + '/versions-rc.json', 'r') as json_versions: print('Checking Linux CachyOS RC') parse_json(json_versions, '-rc') with open(root + '/versions-lts.json', 'r') as json_versions: print('Checking Linux CachyOS LTS') parse_json(json_versions, '-lts') with open(root + '/versions-hardened.json', 'r') as json_versions: print('Checking Linux CachyOS Hardened') parse_json(json_versions, '-hardened') ''; in { config = { sops = { age.keyFile = "/home/${config.home.username}/.config/sops/age/keys.txt"; defaultSopsFile = "/etc/nixos/secrets/secrets.yaml"; validateSopsFiles = false; secrets = { "github-token" = { }; }; templates = { ".env".content = '' GITHUB_TOKEN = "${config.sops.placeholder.github-token}" ''; }; }; home.packages = [ update-checker ]; }; }