apt.cli.rs icon indicating copy to clipboard operation
apt.cli.rs copied to clipboard

Where is the source of the web site?

Open szabgab opened this issue 6 months ago • 5 comments

As I understand this repo only contains the main page of https://apt.cli.rs/ Are the rest of the files or the tools that generate them available in a GitHub repo? It would be nice if you linked to that repo in the README file.

szabgab avatar Dec 28 '23 06:12 szabgab

I plan on publishing them at some point, but at the moment they are not public. For now here are the contents of the index.html, and script I use to update the repo:

index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Rust apt repo</title>
    <meta name="viewport" content="width=device-width,minimum-scale=1" />
    <meta charset="UTF-8" />
    <link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
    <link rel="stylesheet" href="css/sakura-dark.css" type="text/css">
    <link rel="stylesheet" href="css/site.css" type="text/css">
</head>
<body>
<h1 id="rust-tools-apt-repo">Rust Tools apt repo</h1>
<p>By <a rel="me" href="https://hachyderm.io/@ethantyping">@[email protected]</a><br><quote>If you appreciate this APT repo, <a href="https://github.com/sponsors/ethanhs" >sponsorship on Github is appreciated!</a></quote></p>
<p>This is a simple apt repo hosting popular Rust tools which you can access at <a href="https://apt.cli.rs">apt.cli.rs</a>.</p>
<p>The plan is to update the repo when these tools make new releases, so you automatically get the latest and greatest (and don&#39;t have to manually install <code>.deb</code> files).</p>
<h3 id="current-packages-available">Current packages available</h3>
<p>Currently the list is somewhat small, but suggestions are welcome! Feel free to file an issue at <a href="https://github.com/ethanhs/apt.cli.rs">https://github.com/ethanhs/apt.cli.rs</a></p>
<ul>
<li><a href="https://github.com/sharkdp/bat">bat</a></li>
<li><a href="https://github.com/dandavison/delta">delta</a></li>
<li><a href="https://github.com/sharkdp/fd">fd</a></li>
<li><a href="https://github.com/jhspetersson/fselect">fselect</a></li>
<li><a href="https://github.com/sharkdp/hexyl">hexyl</a></li>
<li><a href="https://github.com/sharkdp/hyperfine">hyperfine</a></li>
<li><a href="https://github.com/Peltoche/lsd">lsd</a></li>
<li><a href="https://github.com/BurntSushi/ripgrep">ripgrep</a></li>
<li><a href="https://github.com/watchexec/watchexec">watchexec</a></li>
<li><a href="https://github.com/ducaale/xh">xh</a></li>
<li><a href="https://github.com/ajeetdsouza/zoxide">zoxide</a></li>
</ul>
<h3 id="how-to-add-the-repo">How to add the repo</h3>
<pre><code>$ curl -fsSL https://apt.cli.rs/pubkey.asc | sudo tee -a /usr/share/keyrings/rust-tools.asc
$ curl -fsSL https://apt.cli.rs/rust-tools.list | sudo tee /etc/apt/sources.list.d/rust-tools.list
$ sudo apt update
$ apt show ripgrep
</code></pre><h3 id="browsing-the-apt-repo">Browsing the apt repo</h3>
<p>If you want to find the <code>Release</code> or <code>*.deb</code> files yourself, they are available here:</p>
<p><a href="https://apt.cli.rs/pool/">pool</a></p>
<p><a href="https://apt.cli.rs/dists/">dists</a></p>
</body>
</html>
update-repo.py
from github import Github
import os
import re
import urllib.request
import subprocess
import traceback
from datetime import datetime

TOKEN = os.environ['GITHUB_PAT']

PREFIX = '/opt/apt/newpkgs/'

ASSETS = {
    'sharkdp/numbat': re.compile(r'numbat-musl_(?P<version>\d+\.\d+\.\d+)_(?P<arch>.*).deb$'),
    'sharkdp/bat': re.compile(r'bat-musl_(?P<version>\d+\.\d+\.\d+)_(?P<arch>.*).deb$'),
    'dandavison/delta': re.compile(r'git-delta-musl_(?P<version>\d+\.\d+\.\d+)_(?P<arch>.*).deb$'),
    'sharkdp/fd': re.compile(r'fd-musl_(?P<version>\d+\.\d+\.\d+)_(?P<arch>.*).deb$'),
    # TODO: re-enable once producing deb packages again
    #'jhspetersson/fselect': ,
    'sharkdp/hexyl': re.compile(r'hexyl-musl_(?P<version>\d+\.\d+\.\d+)_(?P<arch>.*).deb$'),
    'sharkdp/hyperfine': re.compile(r'hyperfine-musl_(?P<version>\d+\.\d+\.\d+)_(?P<arch>.*).deb$'),
    'Peltoche/lsd': re.compile(r'lsd-musl_(?P<version>\d+\.\d+\.\d+)_(?P<arch>.*).deb$'),
    'BurntSushi/ripgrep': re.compile(r'ripgrep_(?P<version>\d+\.\d+\.\d+)_(?P<arch>.*).deb$'),
    'watchexec/watchexec': re.compile(r'watchexec-(?P<version>\d+\.\d+\.\d+)-(?P<triple>.*)-musl.deb$'),
    'ducaale/xh': re.compile(r'xh_(?P<version>\d+\.\d+\.\d+)_(?P<arch>.*).deb$'),
    'ajeetdsouza/zoxide': re.compile(r'zoxide_(?P<version>\d+\.\d+\.\d+)_(?P<arch>.*).deb$'),
    'sharkdp/pastel': re.compile(r'pastel-musl_(?P<version>\d+\.\d+\.\d+)_(?P<arch>.*).deb$'),
    'bootandy/dust': re.compile(r'du-dust_(?P<version>\d+\.\d+\.\d+)_(?P<arch>.*).deb$'),
}

def most_recent_snapshot():
    proc = subprocess.run(['aptly', 'snapshot', 'list', '-raw'], capture_output=True, cwd=PREFIX)
    if proc.returncode != 0:
        raise RuntimeError("couldn't list snapshots?")
    all_snapshots = proc.stdout.decode()
    return all_snapshots.splitlines()[-1].strip()

def package_in_repo(name, snapshot):
    if name.endswith('.deb'):
        name = name[:-4]
    proc = subprocess.run(['aptly', 'snapshot', 'search', snapshot, name], capture_output=True, cwd=PREFIX)
    if proc.returncode != 0:
        return False
    if proc.stdout.decode().strip() == name:
        return True
    else:
        return False

def download_files(repo, asset_pattern):
    latest_release = repo.get_latest_release()
    assets_to_add = []
    for asset in latest_release.get_assets():
        if asset_pattern.match(asset.name):
            # If already downloaded, nothing to do
            snapshot = most_recent_snapshot()
            if package_in_repo(asset.name, snapshot):
                print(f'Skipping {asset.name}, it has already been added to the repo.')
                continue
            assets_to_add.append(PREFIX + asset.name)
            print(f'Downloading {asset.name}')
            try:
                file, _headers = urllib.request.urlretrieve(asset.browser_download_url, filename=PREFIX + asset.name)
                print(file)
            except urllib.request.HTTPError:
                print(f'Failed downloading {asset.name} due to the following exception:\n')
                traceback.print_exc()
    return assets_to_add


def add_to_repo(assets_to_add):
    print(f'Adding {len(assets_to_add)} assets to the repo.')
    for asset in assets_to_add:
        try:
            cmdline = ['aptly', 'repo', 'add', 'rust-tools', asset]
            print(*cmdline)
            proc = subprocess.run(cmdline, capture_output=True, cwd=PREFIX)
        except subprocess.CalledProcessError:
            print(f'Failed to add asset {asset}:\n')
            traceback.print_exc()
        else:
            print(proc.stdout.decode(), proc.stderr.decode(), sep='\n')


def create_snapshot():
    snapshot_name = f'rust-tools-{datetime.strftime(datetime.now(), "%Y/%m/%d-%H:%M:%S")}'
    print(f'Creating snapshot {snapshot_name}')
    try:
        proc = subprocess.run(['aptly', 'snapshot', 'create', snapshot_name, 'from', 'repo', 'rust-tools'], capture_output=True, cwd=PREFIX)
    except subprocess.CalledProcessError:
        print(f'Failed to create snapshot {snapshot_name}')
        traceback.print_exc()
    else:
        print(proc.stdout.decode(), proc.stderr.decode(), sep='\n')
    return snapshot_name

def publish_snapshot(snapshot):
    print(f'Publishing snapshot {snapshot}')
    try:
        proc = subprocess.run(['aptly', 'publish', 'switch', 'all', snapshot], capture_output=True, cwd=PREFIX)
    except subprocess.CalledProcessError:
        print(f'Failed to publish snapshot {snapshot}')
        traceback.print_exc()
    else:
        print(proc.stdout.decode(), proc.stderr.decode(), sep='\n')

def update_repo(repo, asset_pattern):
    assets_to_add = download_files(repo, asset_pattern)
    add_to_repo(assets_to_add)


def main():
    g = Github(TOKEN)
    for (repo, asset_pattern) in ASSETS.items():
        print(f'Updating {repo}...')
        try:
            update_repo(g.get_repo(repo), asset_pattern)
        except Exception:
            traceback.print_exc()
        print('Done!')
    snapshot = create_snapshot()
    publish_snapshot(snapshot)

if __name__ == '__main__':
    main()

At some point (maybe I'll do it this weekend) I want to push these files to Github so they are version controlled I just haven't bothered yet. Let me know if you have any questions about how the script works or anything, happy to answer questions.

ethanhs avatar Dec 28 '23 08:12 ethanhs

(Also I'm about to update index.html with numbat, which I just added to the repo).

ethanhs avatar Dec 28 '23 08:12 ethanhs

Thanks for the quick reply. I was primarily interested as I was collecting information about open source applications written in Rust and wanted to include more details about each project.

szabgab avatar Dec 28 '23 08:12 szabgab

Ah, well I expect you'd be interested in the actual CLI tools themselves, which are all linked from the readme. I only make them available in an apt repo.

ethanhs avatar Dec 28 '23 21:12 ethanhs

Yeah, probably those are more important for the list, but I think it is a good idea to keep your project there too.

szabgab avatar Jan 01 '24 07:01 szabgab