spyco

Untitled

Nov 13th, 2025
297
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 13.68 KB | None | 0 0
  1. #!/usr/bin/env bash
  2. # install-curlai.sh
  3. # Installer for Curl Ai project
  4. # Creates project directory under ~/.git/curlai
  5. # Initializes a git repo, creates python package layout, virtualenv,
  6. # helper scripts in ~/bin, sample tests, README, LICENSE, and performs initial commit.
  7. # Written to be idempotent and safe for Debian/Ubuntu (non-destructive checks).
  8.  
  9. set -euo pipefail
  10. IFS=$'\n\t'
  11.  
  12. # -----------------------------
  13. # Configuration (edit if needed)
  14. # -----------------------------
  15. PROJECT_BASE="$HOME/.git"
  16. PROJECT_NAME="curlai"
  17. PROJECT_DIR="$PROJECT_BASE/$PROJECT_NAME"
  18. BIN_DIR="$HOME/bin"                  # user bin directory for helper scripts
  19. PYTHON_BIN="python3"                 # python executable to use
  20. VENV_DIR="$PROJECT_DIR/.venv"        # virtualenv location
  21. GIT_NAME="REDACTED"                  # git author name used for initial commit
  22. GIT_EMAIL="${GIT_NAME}@example.local"
  23. VERSION="v1.0"
  24. PROFILE_URL="https://x.com/BayouCityBum"
  25. LICENSE_TYPE="MIT"
  26.  
  27. # -----------------------------
  28. # Helpers
  29. # -----------------------------
  30. info() { printf "[INFO] %s\n" "$*"; }
  31. err()  { printf "[ERROR] %s\n" "$*" >&2; }
  32.  
  33. # Ensure ~/bin exists and is on PATH for this script's session
  34. mkdir -p "$BIN_DIR"
  35. if [[ ":$PATH:" != *":$BIN_DIR:"* ]]; then
  36.   export PATH="$BIN_DIR:$PATH"
  37.   info "Added $BIN_DIR to PATH for this session. Add to your shell rc to persist."
  38. fi
  39.  
  40. # -----------------------------
  41. # Pre-flight: required tools
  42. # -----------------------------
  43. need_cmds=(git $PYTHON_BIN pip3)
  44. missing=()
  45. for cmd in "${need_cmds[@]}"; do
  46.   if ! command -v "$cmd" >/dev/null 2>&1; then
  47.     missing+=("$cmd")
  48.   fi
  49. done
  50.  
  51. if (( ${#missing[@]} > 0 )); then
  52.   info "Missing commands: ${missing[*]}"
  53.   # Try to install via apt-get if available
  54.   if command -v apt-get >/dev/null 2>&1; then
  55.     info "Attempting to install missing packages with apt-get (requires sudo)."
  56.     sudo apt-get update -y
  57.     sudo apt-get install -y git python3 python3-venv python3-pip || {
  58.       err "Automatic install failed. Please install: ${missing[*]} and re-run this script.";
  59.       exit 1
  60.     }
  61.   else
  62.     err "Non-interactive installer can't install missing tools on this platform. Please install: ${missing[*]}"
  63.     exit 1
  64.   fi
  65. fi
  66.  
  67. # -----------------------------
  68. # Create project directories
  69. # -----------------------------
  70. info "Creating project directories under: $PROJECT_DIR"
  71. mkdir -p "$PROJECT_DIR"
  72. mkdir -p "$PROJECT_DIR/src/$PROJECT_NAME"     # package sources
  73. mkdir -p "$PROJECT_DIR/tests"
  74. mkdir -p "$PROJECT_DIR/docs"
  75. mkdir -p "$PROJECT_DIR/examples"
  76. mkdir -p "$PROJECT_DIR/logs"
  77. mkdir -p "$PROJECT_DIR/assets"
  78.  
  79. # -----------------------------
  80. # Create README.md
  81. # -----------------------------
  82. cat > "$PROJECT_DIR/README.md" <<'README'
  83. # Curl Ai
  84.  
  85. Project: Curl Ai
  86.  
  87. Author: REDACTED
  88. Profile: https://x.com/BayouCityBum
  89. Version: v1.0
  90.  
  91. This repository contains a lightweight Python-based CLI/web helper for working with cURL-style workflows and integrations with small local LLM tooling.
  92.  
  93. Folders created by the installer:
  94. - src/: Python package source
  95. - tests/: pytest tests
  96. - docs/: documentation and notes
  97. - examples/: runnable examples
  98. - logs/: runtime logs
  99. - assets/: sample assets (images, thumbnails)
  100.  
  101. How to use:
  102. 1. Source virtualenv: `source .venv/bin/activate`
  103. 2. Install dependencies: `pip install -r requirements.txt` (installer already runs this)
  104. 3. Run: `./run.sh` or `bin/run-curlai.sh`
  105.  
  106. README
  107.  
  108. # -----------------------------
  109. # Create LICENSE (MIT)
  110. # -----------------------------
  111. cat > "$PROJECT_DIR/LICENSE" <<'LICENSE'
  112. MIT License
  113.  
  114. Copyright (c) $(date +%Y) REDACTED
  115.  
  116. Permission is hereby granted, free of charge, to any person obtaining a copy
  117. of this software and associated documentation files (the "Software"), to deal
  118. in the Software without restriction, including without limitation the rights
  119. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  120. copies of the Software, and to permit persons to whom the Software is
  121. furnished to do so, subject to the following conditions:
  122.  
  123. The above copyright notice and this permission notice shall be included in all
  124. copies or substantial portions of the Software.
  125.  
  126. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  127. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  128. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  129. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  130. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  131. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  132. SOFTWARE.
  133.  
  134. LICENSE
  135.  
  136. # -----------------------------
  137. # .gitignore
  138. # -----------------------------
  139. cat > "$PROJECT_DIR/.gitignore" <<'.GITIGNORE'
  140. # Byte-compiled / optimized / DLL files
  141. __pycache__/
  142. *.py[cod]
  143. *$py.class
  144.  
  145. # Virtual environment
  146. .venv/
  147.  
  148. # Distribution / packaging
  149. build/
  150. dist/
  151. *.egg-info/
  152.  
  153. # Logs
  154. logs/
  155. *.log
  156.  
  157. # System files
  158. .DS_Store
  159. .GITIGNORE
  160.  
  161. # -----------------------------
  162. # pyproject.toml and setup.cfg
  163. # -----------------------------
  164. cat > "$PROJECT_DIR/pyproject.toml" <<'PYPROJECT'
  165. [build-system]
  166. requires = ["setuptools>=61.0", "wheel"]
  167. build-backend = "setuptools.build_meta"
  168.  
  169. [project]
  170. name = "curlai"
  171. version = "1.0.0"
  172. description = "Curl Ai - helper tools around curl workflows and LLM integrations"
  173. authors = [ {name = "REDACTED", url = "https://x.com/BayouCityBum"} ]
  174. readme = "README.md"
  175. license = {text = "MIT"}
  176. dependencies = [ ]
  177.  
  178. PYPROJECT
  179.  
  180. # -----------------------------
  181. # requirements.txt
  182. # -----------------------------
  183. cat > "$PROJECT_DIR/requirements.txt" <<'REQS'
  184. # Pin lightweight dependencies for now; update as needed
  185. requests>=2.28
  186. flask>=2.2
  187. pytest>=7.0
  188. yt-dlp>=2023.12.1
  189. REQS
  190.  
  191. # -----------------------------
  192. # Create sample python package files
  193. # -----------------------------
  194. PKG_DIR="$PROJECT_DIR/src/$PROJECT_NAME"
  195.  
  196. # __init__.py: package metadata and version
  197. cat > "$PKG_DIR/__init__.py" <<'PYINIT'
  198. """
  199. Curl Ai package initializer.
  200. Contains package version, metadata and the public API surface.
  201. """
  202.  
  203. # Semantic version (kept in sync with installer VERSION variable)
  204. __version__ = "1.0.0"
  205.  
  206. # Basic metadata
  207. __author__ = "REDACTED"
  208. __profile__ = "https://x.com/BayouCityBum"
  209.  
  210. # Export primary entrypoints
  211. from .main import main  # re-export main for direct package execution
  212.  
  213. PYINIT
  214.  
  215. # main.py: simple CLI entrypoint with detailed comments
  216. cat > "$PKG_DIR/main.py" <<'MAIN'
  217. """
  218. Main module for Curl Ai.
  219. Provides a tiny CLI and web entrypoint for demonstration.
  220. """
  221. import argparse
  222. import os
  223. import sys
  224.  
  225. # Import local utilities (kept minimal and well-commented)
  226. from . import __version__
  227. from .utils import run_shell, download_url
  228.  
  229.  
  230. def cli(argv=None):
  231.    """Parse command-line arguments and dispatch commands.
  232.  
  233.     Args:
  234.         argv (list|None): list of CLI args (for testing). If None, uses sys.argv[1:]
  235.     Returns:
  236.         int: exit code
  237.     """
  238.    parser = argparse.ArgumentParser(prog="curlai", description="Curl Ai CLI")
  239.    parser.add_argument("--version", action="store_true", help="print version and exit")
  240.    parser.add_argument("--fetch", metavar="URL", help="download a URL via requests")
  241.  
  242.    args = parser.parse_args(argv)
  243.  
  244.    if args.version:
  245.        print(f"curlai {__version__}")
  246.        return 0
  247.  
  248.    if args.fetch:
  249.        out = download_url(args.fetch)
  250.        print(out[:100] + "..." if len(out) > 100 else out)
  251.        return 0
  252.  
  253.    parser.print_help()
  254.    return 2
  255.  
  256.  
  257. def main():
  258.    """Main program entry used when running as module: python -m curlai
  259.     Keep main minimal so unit tests can import cli() directly.
  260.     """
  261.    raise SystemExit(cli())
  262.  
  263. # Allow execution as a script
  264. if __name__ == "__main__":
  265.    main()
  266.  
  267. MAIN
  268.  
  269. # utils.py: helper functions with verbose comments
  270. cat > "$PKG_DIR/utils.py" <<'UTILS'
  271. """
  272. Utility functions used by Curl Ai.
  273. All functions are small, explicit, and well-commented for learning.
  274. """
  275. import subprocess
  276. import requests
  277.  
  278.  
  279. def run_shell(cmd, timeout=30):
  280.    """Run a shell command and return stdout.
  281.  
  282.     Args:
  283.         cmd (list|str): command to run (if list, recommended to avoid shell=True)
  284.         timeout (int): seconds before timeout
  285.     Returns:
  286.         str: stdout of command
  287.     Raises:
  288.         subprocess.CalledProcessError on non-zero exit
  289.     """
  290.    if isinstance(cmd, str):
  291.        cmd = cmd.split()
  292.    result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=timeout)
  293.    result.check_returncode()  # will raise CalledProcessError if exit != 0
  294.    return result.stdout
  295.  
  296.  
  297. def download_url(url, timeout=15):
  298.    """Download the supplied URL and return text.
  299.     This is a small wrapper around requests.get with basic error handling.
  300.     """
  301.    r = requests.get(url, timeout=timeout)
  302.    r.raise_for_status()
  303.    return r.text
  304.  
  305. UTILS
  306.  
  307. # -----------------------------
  308. # Example script in examples/
  309. # -----------------------------
  310. cat > "$PROJECT_DIR/examples/demo_fetch.py" <<'DEMO'
  311. """
  312. Example demonstrating using the curlai package to fetch a URL.
  313. Run: python examples/demo_fetch.py
  314. """
  315. from src.curlai.utils import download_url
  316.  
  317. if __name__ == "__main__":
  318.    print(download_url("https://httpbin.org/get")[:300])
  319.  
  320. DEMO
  321.  
  322. # -----------------------------
  323. # Tests (pytest)
  324. # -----------------------------
  325. cat > "$PROJECT_DIR/tests/test_basic.py" <<'TEST'
  326. """
  327. Basic unit tests for the curlai package.
  328. These are intentionally simple to verify package import and basic functions.
  329. """
  330. import importlib
  331.  
  332.  
  333. def test_import_main():
  334.    # Ensure package imports successfully
  335.    mod = importlib.import_module('src.curlai')
  336.    assert hasattr(mod, '__version__')
  337.  
  338.  
  339. def test_utils_download(monkeypatch):
  340.    # Sanity test for download_url using monkeypatch to avoid network
  341.    import src.curlai.utils as utils
  342.  
  343.    class DummyResp:
  344.        status_code = 200
  345.        text = 'ok'
  346.        def raise_for_status(self):
  347.            return None
  348.  
  349.    def fake_get(url, timeout=0):
  350.        return DummyResp()
  351.  
  352.    import requests
  353.    monkeypatch.setattr(requests, 'get', fake_get)
  354.    assert utils.download_url('http://example') == 'ok'
  355.  
  356. TEST
  357.  
  358. # -----------------------------
  359. # Create simple runner and helper scripts in project root and ~/bin
  360. # -----------------------------
  361. RUN_SH="$PROJECT_DIR/run.sh"
  362. cat > "$RUN_SH" <<'RUN'
  363. #!/usr/bin/env bash
  364. # run.sh - run the curlai CLI inside the project's venv
  365. # This script activates the venv (if present) and executes the curlai package
  366. set -euo pipefail
  367. source "$(dirname "$0")/.venv/bin/activate" || true
  368. python -m src.curlai.main "$@"
  369. RUN
  370. chmod +x "$RUN_SH"
  371.  
  372. # bin/run-curlai.sh: global helper in ~/bin to run the project from anywhere
  373. BIN_RUN="$BIN_DIR/run-curlai.sh"
  374. cat > "$BIN_RUN" <<'BINRUN'
  375. #!/usr/bin/env bash
  376. # run-curlai.sh - global helper to locate the curlai project and run it
  377. # Locates project under ~/.git/curlai by default
  378. set -euo pipefail
  379. PROJECT_DIR="$HOME/.git/curlai"
  380. if [[ ! -d "$PROJECT_DIR" ]]; then
  381.  echo "Project not found at $PROJECT_DIR" >&2
  382.  exit 2
  383. fi
  384. # Activate venv if present
  385. if [[ -f "$PROJECT_DIR/.venv/bin/activate" ]]; then
  386.  # shellcheck disable=SC1091
  387.  source "$PROJECT_DIR/.venv/bin/activate"
  388. fi
  389. python -m src.curlai.main "$@"
  390. BINRUN
  391. chmod +x "$BIN_RUN"
  392.  
  393. # helper test runner
  394. cat > "$PROJECT_DIR/test.sh" <<'TSTR'
  395. #!/usr/bin/env bash
  396. # test.sh - run pytest inside venv
  397. set -euo pipefail
  398. source "$(dirname "$0")/.venv/bin/activate" || true
  399. pytest -q "$@"
  400. TSTR
  401. chmod +x "$PROJECT_DIR/test.sh"
  402.  
  403. # -----------------------------
  404. # Create a simple Dockerfile (optional) and .env.example
  405. # -----------------------------
  406. cat > "$PROJECT_DIR/Dockerfile" <<'DOCKER'
  407. # Minimal image for running curlai
  408. FROM python:3.11-slim
  409. WORKDIR /app
  410. COPY . /app
  411. RUN pip install --no-cache-dir -r requirements.txt
  412. CMD ["python", "-m", "src.curlai.main"]
  413. DOCKER
  414.  
  415. cat > "$PROJECT_DIR/.env.example" <<'DOTENV'
  416. # Example environment variables
  417. CURLAI_DEBUG=1
  418. DOTENV
  419.  
  420. # -----------------------------
  421. # Create a simple CHANGELOG and meta file
  422. # -----------------------------
  423. cat > "$PROJECT_DIR/CHANGELOG.md" <<'CHANGE'
  424. # Changelog
  425.  
  426. ## v1.0 - Initial
  427. - Project scaffolding
  428. CHANGE
  429.  
  430. cat > "$PROJECT_DIR/META" <<META
  431. name: Curl Ai
  432. author: $GIT_NAME
  433. version: $VERSION
  434. profile: $PROFILE_URL
  435. META
  436.  
  437. # -----------------------------
  438. # Initialize git repo if not already
  439. # -----------------------------
  440. if [[ ! -d "$PROJECT_DIR/.git" ]]; then
  441.  info "Initializing git repo in $PROJECT_DIR"
  442.  git init "$PROJECT_DIR"
  443.  git -C "$PROJECT_DIR" config user.name "$GIT_NAME"
  444.  git -C "$PROJECT_DIR" config user.email "$GIT_EMAIL"
  445.  # Add files and commit
  446.  git -C "$PROJECT_DIR" add .
  447.  git -C "$PROJECT_DIR" commit -m "chore: initial scaffold for $PROJECT_NAME ($VERSION)"
  448. else
  449.  info "Git repo already exists at $PROJECT_DIR — skipping git init"
  450. fi
  451.  
  452. # -----------------------------
  453. # Create virtualenv and install requirements
  454. # -----------------------------
  455. if [[ ! -d "$VENV_DIR" ]]; then
  456.  info "Creating virtualenv at $VENV_DIR"
  457.  $PYTHON_BIN -m venv "$VENV_DIR"
  458. fi
  459. # Activate and install
  460. # shellcheck disable=SC1091
  461. source "$VENV_DIR/bin/activate"
  462. info "Upgrading pip and installing requirements"
  463. python -m pip install --upgrade pip >/dev/null
  464. pip install -r "$PROJECT_DIR/requirements.txt"
  465.  
  466. # -----------------------------
  467. # Success summary and next steps
  468. # -----------------------------
  469. info "Setup completed. Project created at: $PROJECT_DIR"
  470. info "Helper run script at: $BIN_RUN"
  471. info "To start using the project now:"
  472. cat <<EOF
  473.  cd $PROJECT_DIR
  474.  source $VENV_DIR/bin/activate
  475.  $BIN_RUN --version
  476.  # run tests:
  477.  ./test.sh
  478. EOF
  479.  
  480. exit 0
  481.  
Advertisement
Add Comment
Please, Sign In to add comment