Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env bash
- # install-curlai.sh
- # Installer for Curl Ai project
- # Creates project directory under ~/.git/curlai
- # Initializes a git repo, creates python package layout, virtualenv,
- # helper scripts in ~/bin, sample tests, README, LICENSE, and performs initial commit.
- # Written to be idempotent and safe for Debian/Ubuntu (non-destructive checks).
- set -euo pipefail
- IFS=$'\n\t'
- # -----------------------------
- # Configuration (edit if needed)
- # -----------------------------
- PROJECT_BASE="$HOME/.git"
- PROJECT_NAME="curlai"
- PROJECT_DIR="$PROJECT_BASE/$PROJECT_NAME"
- BIN_DIR="$HOME/bin" # user bin directory for helper scripts
- PYTHON_BIN="python3" # python executable to use
- VENV_DIR="$PROJECT_DIR/.venv" # virtualenv location
- GIT_NAME="REDACTED" # git author name used for initial commit
- GIT_EMAIL="${GIT_NAME}@example.local"
- VERSION="v1.0"
- PROFILE_URL="https://x.com/BayouCityBum"
- LICENSE_TYPE="MIT"
- # -----------------------------
- # Helpers
- # -----------------------------
- info() { printf "[INFO] %s\n" "$*"; }
- err() { printf "[ERROR] %s\n" "$*" >&2; }
- # Ensure ~/bin exists and is on PATH for this script's session
- mkdir -p "$BIN_DIR"
- if [[ ":$PATH:" != *":$BIN_DIR:"* ]]; then
- export PATH="$BIN_DIR:$PATH"
- info "Added $BIN_DIR to PATH for this session. Add to your shell rc to persist."
- fi
- # -----------------------------
- # Pre-flight: required tools
- # -----------------------------
- need_cmds=(git $PYTHON_BIN pip3)
- missing=()
- for cmd in "${need_cmds[@]}"; do
- if ! command -v "$cmd" >/dev/null 2>&1; then
- missing+=("$cmd")
- fi
- done
- if (( ${#missing[@]} > 0 )); then
- info "Missing commands: ${missing[*]}"
- # Try to install via apt-get if available
- if command -v apt-get >/dev/null 2>&1; then
- info "Attempting to install missing packages with apt-get (requires sudo)."
- sudo apt-get update -y
- sudo apt-get install -y git python3 python3-venv python3-pip || {
- err "Automatic install failed. Please install: ${missing[*]} and re-run this script.";
- exit 1
- }
- else
- err "Non-interactive installer can't install missing tools on this platform. Please install: ${missing[*]}"
- exit 1
- fi
- fi
- # -----------------------------
- # Create project directories
- # -----------------------------
- info "Creating project directories under: $PROJECT_DIR"
- mkdir -p "$PROJECT_DIR"
- mkdir -p "$PROJECT_DIR/src/$PROJECT_NAME" # package sources
- mkdir -p "$PROJECT_DIR/tests"
- mkdir -p "$PROJECT_DIR/docs"
- mkdir -p "$PROJECT_DIR/examples"
- mkdir -p "$PROJECT_DIR/logs"
- mkdir -p "$PROJECT_DIR/assets"
- # -----------------------------
- # Create README.md
- # -----------------------------
- cat > "$PROJECT_DIR/README.md" <<'README'
- # Curl Ai
- Project: Curl Ai
- Author: REDACTED
- Profile: https://x.com/BayouCityBum
- Version: v1.0
- This repository contains a lightweight Python-based CLI/web helper for working with cURL-style workflows and integrations with small local LLM tooling.
- Folders created by the installer:
- - src/: Python package source
- - tests/: pytest tests
- - docs/: documentation and notes
- - examples/: runnable examples
- - logs/: runtime logs
- - assets/: sample assets (images, thumbnails)
- How to use:
- 1. Source virtualenv: `source .venv/bin/activate`
- 2. Install dependencies: `pip install -r requirements.txt` (installer already runs this)
- 3. Run: `./run.sh` or `bin/run-curlai.sh`
- README
- # -----------------------------
- # Create LICENSE (MIT)
- # -----------------------------
- cat > "$PROJECT_DIR/LICENSE" <<'LICENSE'
- MIT License
- Copyright (c) $(date +%Y) REDACTED
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- LICENSE
- # -----------------------------
- # .gitignore
- # -----------------------------
- cat > "$PROJECT_DIR/.gitignore" <<'.GITIGNORE'
- # Byte-compiled / optimized / DLL files
- __pycache__/
- *.py[cod]
- *$py.class
- # Virtual environment
- .venv/
- # Distribution / packaging
- build/
- dist/
- *.egg-info/
- # Logs
- logs/
- *.log
- # System files
- .DS_Store
- .GITIGNORE
- # -----------------------------
- # pyproject.toml and setup.cfg
- # -----------------------------
- cat > "$PROJECT_DIR/pyproject.toml" <<'PYPROJECT'
- [build-system]
- requires = ["setuptools>=61.0", "wheel"]
- build-backend = "setuptools.build_meta"
- [project]
- name = "curlai"
- version = "1.0.0"
- description = "Curl Ai - helper tools around curl workflows and LLM integrations"
- authors = [ {name = "REDACTED", url = "https://x.com/BayouCityBum"} ]
- readme = "README.md"
- license = {text = "MIT"}
- dependencies = [ ]
- PYPROJECT
- # -----------------------------
- # requirements.txt
- # -----------------------------
- cat > "$PROJECT_DIR/requirements.txt" <<'REQS'
- # Pin lightweight dependencies for now; update as needed
- requests>=2.28
- flask>=2.2
- pytest>=7.0
- yt-dlp>=2023.12.1
- REQS
- # -----------------------------
- # Create sample python package files
- # -----------------------------
- PKG_DIR="$PROJECT_DIR/src/$PROJECT_NAME"
- # __init__.py: package metadata and version
- cat > "$PKG_DIR/__init__.py" <<'PYINIT'
- """
- Curl Ai package initializer.
- Contains package version, metadata and the public API surface.
- """
- # Semantic version (kept in sync with installer VERSION variable)
- __version__ = "1.0.0"
- # Basic metadata
- __author__ = "REDACTED"
- __profile__ = "https://x.com/BayouCityBum"
- # Export primary entrypoints
- from .main import main # re-export main for direct package execution
- PYINIT
- # main.py: simple CLI entrypoint with detailed comments
- cat > "$PKG_DIR/main.py" <<'MAIN'
- """
- Main module for Curl Ai.
- Provides a tiny CLI and web entrypoint for demonstration.
- """
- import argparse
- import os
- import sys
- # Import local utilities (kept minimal and well-commented)
- from . import __version__
- from .utils import run_shell, download_url
- def cli(argv=None):
- """Parse command-line arguments and dispatch commands.
- Args:
- argv (list|None): list of CLI args (for testing). If None, uses sys.argv[1:]
- Returns:
- int: exit code
- """
- parser = argparse.ArgumentParser(prog="curlai", description="Curl Ai CLI")
- parser.add_argument("--version", action="store_true", help="print version and exit")
- parser.add_argument("--fetch", metavar="URL", help="download a URL via requests")
- args = parser.parse_args(argv)
- if args.version:
- print(f"curlai {__version__}")
- return 0
- if args.fetch:
- out = download_url(args.fetch)
- print(out[:100] + "..." if len(out) > 100 else out)
- return 0
- parser.print_help()
- return 2
- def main():
- """Main program entry used when running as module: python -m curlai
- Keep main minimal so unit tests can import cli() directly.
- """
- raise SystemExit(cli())
- # Allow execution as a script
- if __name__ == "__main__":
- main()
- MAIN
- # utils.py: helper functions with verbose comments
- cat > "$PKG_DIR/utils.py" <<'UTILS'
- """
- Utility functions used by Curl Ai.
- All functions are small, explicit, and well-commented for learning.
- """
- import subprocess
- import requests
- def run_shell(cmd, timeout=30):
- """Run a shell command and return stdout.
- Args:
- cmd (list|str): command to run (if list, recommended to avoid shell=True)
- timeout (int): seconds before timeout
- Returns:
- str: stdout of command
- Raises:
- subprocess.CalledProcessError on non-zero exit
- """
- if isinstance(cmd, str):
- cmd = cmd.split()
- result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=timeout)
- result.check_returncode() # will raise CalledProcessError if exit != 0
- return result.stdout
- def download_url(url, timeout=15):
- """Download the supplied URL and return text.
- This is a small wrapper around requests.get with basic error handling.
- """
- r = requests.get(url, timeout=timeout)
- r.raise_for_status()
- return r.text
- UTILS
- # -----------------------------
- # Example script in examples/
- # -----------------------------
- cat > "$PROJECT_DIR/examples/demo_fetch.py" <<'DEMO'
- """
- Example demonstrating using the curlai package to fetch a URL.
- Run: python examples/demo_fetch.py
- """
- from src.curlai.utils import download_url
- if __name__ == "__main__":
- print(download_url("https://httpbin.org/get")[:300])
- DEMO
- # -----------------------------
- # Tests (pytest)
- # -----------------------------
- cat > "$PROJECT_DIR/tests/test_basic.py" <<'TEST'
- """
- Basic unit tests for the curlai package.
- These are intentionally simple to verify package import and basic functions.
- """
- import importlib
- def test_import_main():
- # Ensure package imports successfully
- mod = importlib.import_module('src.curlai')
- assert hasattr(mod, '__version__')
- def test_utils_download(monkeypatch):
- # Sanity test for download_url using monkeypatch to avoid network
- import src.curlai.utils as utils
- class DummyResp:
- status_code = 200
- text = 'ok'
- def raise_for_status(self):
- return None
- def fake_get(url, timeout=0):
- return DummyResp()
- import requests
- monkeypatch.setattr(requests, 'get', fake_get)
- assert utils.download_url('http://example') == 'ok'
- TEST
- # -----------------------------
- # Create simple runner and helper scripts in project root and ~/bin
- # -----------------------------
- RUN_SH="$PROJECT_DIR/run.sh"
- cat > "$RUN_SH" <<'RUN'
- #!/usr/bin/env bash
- # run.sh - run the curlai CLI inside the project's venv
- # This script activates the venv (if present) and executes the curlai package
- set -euo pipefail
- source "$(dirname "$0")/.venv/bin/activate" || true
- python -m src.curlai.main "$@"
- RUN
- chmod +x "$RUN_SH"
- # bin/run-curlai.sh: global helper in ~/bin to run the project from anywhere
- BIN_RUN="$BIN_DIR/run-curlai.sh"
- cat > "$BIN_RUN" <<'BINRUN'
- #!/usr/bin/env bash
- # run-curlai.sh - global helper to locate the curlai project and run it
- # Locates project under ~/.git/curlai by default
- set -euo pipefail
- PROJECT_DIR="$HOME/.git/curlai"
- if [[ ! -d "$PROJECT_DIR" ]]; then
- echo "Project not found at $PROJECT_DIR" >&2
- exit 2
- fi
- # Activate venv if present
- if [[ -f "$PROJECT_DIR/.venv/bin/activate" ]]; then
- # shellcheck disable=SC1091
- source "$PROJECT_DIR/.venv/bin/activate"
- fi
- python -m src.curlai.main "$@"
- BINRUN
- chmod +x "$BIN_RUN"
- # helper test runner
- cat > "$PROJECT_DIR/test.sh" <<'TSTR'
- #!/usr/bin/env bash
- # test.sh - run pytest inside venv
- set -euo pipefail
- source "$(dirname "$0")/.venv/bin/activate" || true
- pytest -q "$@"
- TSTR
- chmod +x "$PROJECT_DIR/test.sh"
- # -----------------------------
- # Create a simple Dockerfile (optional) and .env.example
- # -----------------------------
- cat > "$PROJECT_DIR/Dockerfile" <<'DOCKER'
- # Minimal image for running curlai
- FROM python:3.11-slim
- WORKDIR /app
- COPY . /app
- RUN pip install --no-cache-dir -r requirements.txt
- CMD ["python", "-m", "src.curlai.main"]
- DOCKER
- cat > "$PROJECT_DIR/.env.example" <<'DOTENV'
- # Example environment variables
- CURLAI_DEBUG=1
- DOTENV
- # -----------------------------
- # Create a simple CHANGELOG and meta file
- # -----------------------------
- cat > "$PROJECT_DIR/CHANGELOG.md" <<'CHANGE'
- # Changelog
- ## v1.0 - Initial
- - Project scaffolding
- CHANGE
- cat > "$PROJECT_DIR/META" <<META
- name: Curl Ai
- author: $GIT_NAME
- version: $VERSION
- profile: $PROFILE_URL
- META
- # -----------------------------
- # Initialize git repo if not already
- # -----------------------------
- if [[ ! -d "$PROJECT_DIR/.git" ]]; then
- info "Initializing git repo in $PROJECT_DIR"
- git init "$PROJECT_DIR"
- git -C "$PROJECT_DIR" config user.name "$GIT_NAME"
- git -C "$PROJECT_DIR" config user.email "$GIT_EMAIL"
- # Add files and commit
- git -C "$PROJECT_DIR" add .
- git -C "$PROJECT_DIR" commit -m "chore: initial scaffold for $PROJECT_NAME ($VERSION)"
- else
- info "Git repo already exists at $PROJECT_DIR — skipping git init"
- fi
- # -----------------------------
- # Create virtualenv and install requirements
- # -----------------------------
- if [[ ! -d "$VENV_DIR" ]]; then
- info "Creating virtualenv at $VENV_DIR"
- $PYTHON_BIN -m venv "$VENV_DIR"
- fi
- # Activate and install
- # shellcheck disable=SC1091
- source "$VENV_DIR/bin/activate"
- info "Upgrading pip and installing requirements"
- python -m pip install --upgrade pip >/dev/null
- pip install -r "$PROJECT_DIR/requirements.txt"
- # -----------------------------
- # Success summary and next steps
- # -----------------------------
- info "Setup completed. Project created at: $PROJECT_DIR"
- info "Helper run script at: $BIN_RUN"
- info "To start using the project now:"
- cat <<EOF
- cd $PROJECT_DIR
- source $VENV_DIR/bin/activate
- $BIN_RUN --version
- # run tests:
- ./test.sh
- EOF
- exit 0
Advertisement
Add Comment
Please, Sign In to add comment