apt.cli.rs
apt.cli.rs copied to clipboard
Where is the source of the web site?
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.
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'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.
(Also I'm about to update index.html with numbat, which I just added to the repo).
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.
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.
Yeah, probably those are more important for the list, but I think it is a good idea to keep your project there too.