Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,5 @@ playwright-report/
test-results/

runongpu-chrome-profile/

.ruff_cache/
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
name = "runongpu"
version = "1.0.2"
description = "A CLI tool that runs GitHub projects on free cloud GPUs"
requires-python = ">=3.12"
requires-python = ">=3.10"
readme = "README.md"

# Runtime dependencies for the CLI.
Expand Down
4 changes: 2 additions & 2 deletions runongpu.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@
[setup]

[build]
cd cuda/vector-add && nvcc main.cu -o vector_add
nvcc test_cuda.cu -o test_cuda

[test]

[run]
cd cuda/vector-add && ./vector_add
./test_cuda
39 changes: 27 additions & 12 deletions runongpu/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,27 @@
# Prints styled terminal output for a better CLI experience.
from rich.console import Console

# Project helpers for saving local config, creating runongpu.txt, and loading user settings.
from runongpu.config import create_runongpu_template_file, get_folder_name_from_repo_url, save_notebook_url, save_repo_url, load_config
from runongpu.colab import open_colab
from runongpu.parser import parse_config

# Project helpers for saving local config, creating runongpu.txt, and loading user settings.
from runongpu.config import (
create_runongpu_template_file,
get_folder_name_from_repo_url,
load_config,
save_notebook_url,
save_repo_url,
)
from runongpu.parser import parse_config

app = typer.Typer()
console = Console()


@app.command()
def doctor():

# Verifies that the user's local RunOnGPU setup has the required pieces installed.
console.print("[bold cyan]Checking RunOnGPU setup...[/bold cyan]")
"""Verifies that the user's local RunOnGPU setup has the required pieces installed."""

console.print("[bold cyan]Checking RunOnGPU setup...[/bold cyan]")
console.print("[green]✓ CLI is running[/green]")
console.print("[green]✓ Typer is installed[/green]")
console.print("[green]✓ Rich is installed[/green]")
Expand All @@ -31,10 +36,11 @@ def doctor():
console.print("[yellow]Run: runongpu init[/yellow]")
else:
console.print("[green]✓ Repo URL is saved[/green]")
console.print(f"[green] Repo URL: {saved_config["repo_url"]}")
console.print(f"[green] Repo URL: {saved_config['repo_url']}[/green]")

try:
import playwright
import playwright # noqa: F401

console.print("[green]✓ Playwright is installed[/green]")
except ImportError:
console.print("[red]✗ Playwright is not installed[/red]")
Expand All @@ -43,7 +49,8 @@ def doctor():

@app.command()
def init():
# Store the GitHub repo that RunOnGPU should clone inside Colab.
"""Save the repository configuration and create runongpu.txt."""

repo_url = typer.prompt("Enter your Github repo URL")

console.print("[yellow]Deriving folder name[/yellow]")
Expand All @@ -60,7 +67,8 @@ def init():

@app.command()
def config():
# Show the saved local settings without opening Colab.
"""Show the saved local settings without opening Colab."""

saved_config = load_config()

if saved_config is None:
Expand All @@ -80,7 +88,14 @@ def config():

@app.command()
def run():
# Main workflow: parse project commands, open Colab, write the notebook cell, and save the notebook URL.
"""
Main workflow:
- parse project commands,
- open Colab,
- write the notebook cell,
- save the notebook URL.
"""

saved_config = load_config()

if saved_config is None:
Expand All @@ -105,4 +120,4 @@ def run():


if __name__ == "__main__":
app()
app()
15 changes: 7 additions & 8 deletions runongpu/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import json
from pathlib import Path

from rich.console import Console

console = Console()
Expand All @@ -16,12 +17,9 @@


def save_repo_url(repo_url: str, folder_name: str) -> None:

CONFIG_DIR.mkdir(exist_ok=True)
config = {
"repo_url": repo_url,
"notebook_url": "",
"folder_name": folder_name
}
config = {"repo_url": repo_url, "notebook_url": "", "folder_name": folder_name}

# Persist the selected project so future `runongpu run` calls know what to clone.
with open(CONFIG_FILE, "w", encoding="utf-8") as file:
Expand Down Expand Up @@ -58,7 +56,6 @@ def create_runongpu_template_file() -> None:
txt_path = Path("runongpu.txt")

if not txt_path.exists():

txt_path.write_text(
"""# RunOnGPU Configuration
#
Expand Down Expand Up @@ -102,10 +99,12 @@ def create_runongpu_template_file() -> None:
)
console.print("[green]✓ Added runongpu.txt to the repo. [/green]")
else:
console.print("[yellow]runongpu.txt already exists. Good job! Proud of you! [/yellow]")
console.print(
"[yellow]runongpu.txt already exists. Good job! Proud of you! [/yellow]"
)


def get_folder_name_from_repo_url(repo_url: str) -> str:
# Git clones repositories into a folder named after the repo, so derive that
# folder name from the URL instead of asking the user to type it manually.
return repo_url.rstrip("/").split("/")[-1].replace(".git", "")
return repo_url.rstrip("/").split("/")[-1].replace(".git", "")
2 changes: 1 addition & 1 deletion runongpu/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,4 @@ def parse_config() -> dict:

config[current_section].append(line)

return config
return config
2 changes: 1 addition & 1 deletion tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ def test_get_folder_name_from_url_with_trailing_slash():
"https://github.com/MashrafeeAryan/runongpu-examples/"
)

assert result == "runongpu-examples"
assert result == "runongpu-examples"
2 changes: 1 addition & 1 deletion tests/test_config_persistance.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ def test_save_notebook_url_updates_existing_config(tmp_path, monkeypatch):

assert result["repo_url"] == "https://github.com/MashrafeeAryan/RunOnGPU.git"
assert result["folder_name"] == "RunOnGPU"
assert result["notebook_url"] == "https://colab.research.google.com/drive/test"
assert result["notebook_url"] == "https://colab.research.google.com/drive/test"
2 changes: 1 addition & 1 deletion tests/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,4 @@ def test_command_before_section_raises_error(tmp_path, monkeypatch):
monkeypatch.chdir(tmp_path)

with pytest.raises(ValueError, match="Command found before any section header"):
parse_config()
parse_config()
6 changes: 4 additions & 2 deletions tests/test_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ def test_create_runongpu_template_file(tmp_path, monkeypatch):
assert "[run]" in contents


def test_create_runongpu_template_file_does_not_overwrite_existing_file(tmp_path, monkeypatch):
def test_create_runongpu_template_file_does_not_overwrite_existing_file(
tmp_path, monkeypatch
):
# Existing user configs should be preserved instead of overwritten.
monkeypatch.chdir(tmp_path)

Expand All @@ -31,4 +33,4 @@ def test_create_runongpu_template_file_does_not_overwrite_existing_file(tmp_path

create_runongpu_template_file()

assert template_file.read_text(encoding="utf-8") == "[run]\npython main.py\n"
assert template_file.read_text(encoding="utf-8") == "[run]\npython main.py\n"
Loading