Skip to content

Commit 8d5d87c

Browse files
authored
Merge branch 'main' into encoding='utf-8'-correction-&-resolve-.gitignore-&-merge-main
2 parents 76e2337 + d77741b commit 8d5d87c

File tree

14 files changed

+398
-211
lines changed

14 files changed

+398
-211
lines changed

.pre-commit-config.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,10 @@ repos:
7676
rev: v1.36.4
7777
hooks:
7878
- id: djlint-reformat-jinja
79+
80+
- repo: https://github.com/igorshubovych/markdownlint-cli
81+
rev: v0.43.0
82+
hooks:
83+
- id: markdownlint
84+
description: "Lint markdown files."
85+
args: ["--disable=line-length"]

README.md

Lines changed: 25 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,13 @@
1-
[![Image](./docs/frontpage.png "GitIngest main page")](https://gitingest.com)
1+
# GitIngest
22

3-
<!-- License -->
4-
<a href="https://github.com/cyclotruc/gitingest/blob/main/LICENSE">
5-
<img alt="License" src="https://img.shields.io/badge/license-MIT-blue.svg" />
6-
</a>
7-
<!-- PyPI version -->
8-
<a href="https://badge.fury.io/py/gitingest">
9-
<img src="https://badge.fury.io/py/gitingest.svg" alt="PyPI version" />
10-
</a>
11-
<!-- Downloads -->
12-
<a href="https://pepy.tech/project/gitingest">
13-
<img src="https://pepy.tech/badge/gitingest" alt="Downloads" />
14-
</a>
15-
<!-- GitHub issues -->
16-
<a href="https://github.com/cyclotruc/gitingest/issues">
17-
<img src="https://img.shields.io/github/issues/cyclotruc/gitingest" alt="GitHub issues" />
18-
</a>
19-
<!-- Black code style -->
20-
<a href="https://github.com/psf/black">
21-
<img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg" />
22-
</a>
23-
24-
<!-- Discord -->
25-
<a href="https://discord.com/invite/zerRaGK9EC">
26-
<img src="https://dcbadge.limes.pink/api/server/https://discord.com/invite/zerRaGK9EC" alt="Discord" />
27-
</a>
3+
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/cyclotruc/gitingest/blob/main/LICENSE)
4+
[![PyPI version](https://badge.fury.io/py/gitingest.svg)](https://badge.fury.io/py/gitingest)
5+
[![Downloads](https://pepy.tech/badge/gitingest)](https://pepy.tech/project/gitingest)
6+
[![GitHub issues](https://img.shields.io/github/issues/cyclotruc/gitingest)](https://github.com/cyclotruc/gitingest/issues)
7+
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
8+
[![Discord](https://dcbadge.limes.pink/api/server/https://discord.com/invite/zerRaGK9EC)](https://discord.com/invite/zerRaGK9EC)
289

29-
# GitIngest
10+
[![Image](./docs/frontpage.png "GitIngest main page")](https://gitingest.com)
3011

3112
Turn any Git repository into a prompt-friendly text ingest for LLMs.
3213

@@ -92,15 +73,15 @@ By default, this won't write a file but can be enabled with the `output` argumen
9273

9374
1. Build the image:
9475

95-
``` bash
96-
docker build -t gitingest .
97-
```
76+
``` bash
77+
docker build -t gitingest .
78+
```
9879

9980
2. Run the container:
10081

101-
``` bash
102-
docker run -d --name gitingest -p 8000:8000 gitingest
103-
```
82+
``` bash
83+
docker run -d --name gitingest -p 8000:8000 gitingest
84+
```
10485

10586
The application will be available at `http://localhost:8000`
10687
Ensure environment variables are set before running the application or deploying it via Docker.
@@ -135,22 +116,20 @@ ALLOWED_HOSTS="gitingest.local,localhost"
135116

136117
1. Clone the repository
137118

138-
```bash
139-
git clone https://github.com/cyclotruc/gitingest.git
140-
cd gitingest
141-
```
119+
```bash
120+
git clone https://github.com/cyclotruc/gitingest.git
121+
cd gitingest
122+
```
142123

143124
2. Install dependencies
144125

145-
```bash
146-
pip install -r requirements.txt
147-
```
126+
```bash
127+
pip install -r requirements.txt
128+
```
148129

149130
3. Run the application:
150131

151-
```bash
152-
cd src
153-
uvicorn main:app --reload
154-
```
155-
156-
The frontend will be available at `localhost:8000`
132+
```bash
133+
cd src
134+
uvicorn main:app --reload
135+
```

src/config.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
MAX_DISPLAY_SIZE = 300_000
2-
TMP_BASE_PATH = "../tmp"
1+
MAX_DISPLAY_SIZE: int = 300_000
2+
TMP_BASE_PATH: str = "../tmp"
33

4-
EXAMPLE_REPOS = [
4+
EXAMPLE_REPOS: list[dict[str, str]] = [
55
{"name": "Gitingest", "url": "https://github.com/cyclotruc/gitingest"},
66
{"name": "FastAPI", "url": "https://github.com/tiangolo/fastapi"},
77
{"name": "Flask", "url": "https://github.com/pallets/flask"},

src/gitingest/cli.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import os
22
import pathlib
3-
43
import click
54
import sys
65

@@ -13,14 +12,6 @@
1312
# Define constants
1413
DEFAULT_IGNORE_PATTERNS = []
1514

16-
def normalize_pattern(pattern: str) -> str:
17-
pattern = pattern.strip()
18-
pattern = pattern.lstrip(os.sep)
19-
if pattern.endswith(os.sep):
20-
pattern += "*"
21-
return pattern
22-
23-
2415
@click.command()
2516
@click.argument("source", type=str, required=True)
2617
@click.option("--output", "-o", default=None, help="Output file path (default: <repo_name>.txt in current directory)")

src/gitingest/clone.py

Lines changed: 67 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from gitingest.utils import AsyncTimeoutError, async_timeout
55

6-
CLONE_TIMEOUT = 20
6+
CLONE_TIMEOUT: int = 20
77

88

99
@dataclass
@@ -14,67 +14,6 @@ class CloneConfig:
1414
branch: str | None = None
1515

1616

17-
async def check_repo_exists(url: str) -> bool:
18-
"""
19-
Check if a repository exists at the given URL using an HTTP HEAD request.
20-
21-
Parameters
22-
----------
23-
url : str
24-
The URL of the repository.
25-
26-
Returns
27-
-------
28-
bool
29-
True if the repository exists, False otherwise.
30-
"""
31-
proc = await asyncio.create_subprocess_exec(
32-
"curl",
33-
"-I",
34-
url,
35-
stdout=asyncio.subprocess.PIPE,
36-
stderr=asyncio.subprocess.PIPE,
37-
)
38-
stdout, _ = await proc.communicate()
39-
if proc.returncode != 0:
40-
return False
41-
# Check if stdout contains "404" status code
42-
stdout_str = stdout.decode()
43-
return "HTTP/1.1 404" not in stdout_str and "HTTP/2 404" not in stdout_str
44-
45-
46-
async def run_git_command(*args: str) -> tuple[bytes, bytes]:
47-
"""
48-
Executes a git command asynchronously and captures its output.
49-
50-
Parameters
51-
----------
52-
*args : str
53-
The git command and its arguments to execute.
54-
55-
Returns
56-
-------
57-
Tuple[bytes, bytes]
58-
A tuple containing the stdout and stderr of the git command.
59-
60-
Raises
61-
------
62-
RuntimeError
63-
If the git command exits with a non-zero status.
64-
"""
65-
proc = await asyncio.create_subprocess_exec(
66-
*args,
67-
stdout=asyncio.subprocess.PIPE,
68-
stderr=asyncio.subprocess.PIPE,
69-
)
70-
stdout, stderr = await proc.communicate()
71-
if proc.returncode != 0:
72-
error_message = stderr.decode().strip()
73-
raise RuntimeError(f"Git command failed: {' '.join(args)}\nError: {error_message}")
74-
75-
return stdout, stderr
76-
77-
7817
@async_timeout(CLONE_TIMEOUT)
7918
async def clone_repo(config: CloneConfig) -> tuple[bytes, bytes]:
8019
"""
@@ -116,29 +55,90 @@ async def clone_repo(config: CloneConfig) -> tuple[bytes, bytes]:
11655
raise ValueError("The 'local_path' parameter is required.")
11756

11857
# Check if the repository exists
119-
if not await check_repo_exists(url):
58+
if not await _check_repo_exists(url):
12059
raise ValueError("Repository not found, make sure it is public")
12160

12261
try:
12362
if commit:
12463
# Scenario 1: Clone and checkout a specific commit
12564
# Clone the repository without depth to ensure full history for checkout
12665
clone_cmd = ["git", "clone", "--single-branch", url, local_path]
127-
await run_git_command(*clone_cmd)
66+
await _run_git_command(*clone_cmd)
12867

12968
# Checkout the specific commit
13069
checkout_cmd = ["git", "-C", local_path, "checkout", commit]
131-
return await run_git_command(*checkout_cmd)
70+
return await _run_git_command(*checkout_cmd)
13271

13372
if branch and branch.lower() not in ("main", "master"):
13473

13574
# Scenario 2: Clone a specific branch with shallow depth
13675
clone_cmd = ["git", "clone", "--depth=1", "--single-branch", "--branch", branch, url, local_path]
137-
return await run_git_command(*clone_cmd)
76+
return await _run_git_command(*clone_cmd)
13877

13978
# Scenario 3: Clone the default branch with shallow depth
14079
clone_cmd = ["git", "clone", "--depth=1", "--single-branch", url, local_path]
141-
return await run_git_command(*clone_cmd)
80+
return await _run_git_command(*clone_cmd)
14281

14382
except (RuntimeError, asyncio.TimeoutError, AsyncTimeoutError):
14483
raise # Re-raise the exception
84+
85+
86+
async def _check_repo_exists(url: str) -> bool:
87+
"""
88+
Check if a repository exists at the given URL using an HTTP HEAD request.
89+
90+
Parameters
91+
----------
92+
url : str
93+
The URL of the repository.
94+
95+
Returns
96+
-------
97+
bool
98+
True if the repository exists, False otherwise.
99+
"""
100+
proc = await asyncio.create_subprocess_exec(
101+
"curl",
102+
"-I",
103+
url,
104+
stdout=asyncio.subprocess.PIPE,
105+
stderr=asyncio.subprocess.PIPE,
106+
)
107+
stdout, _ = await proc.communicate()
108+
if proc.returncode != 0:
109+
return False
110+
# Check if stdout contains "404" status code
111+
stdout_str = stdout.decode()
112+
return "HTTP/1.1 404" not in stdout_str and "HTTP/2 404" not in stdout_str
113+
114+
115+
async def _run_git_command(*args: str) -> tuple[bytes, bytes]:
116+
"""
117+
Executes a git command asynchronously and captures its output.
118+
119+
Parameters
120+
----------
121+
*args : str
122+
The git command and its arguments to execute.
123+
124+
Returns
125+
-------
126+
Tuple[bytes, bytes]
127+
A tuple containing the stdout and stderr of the git command.
128+
129+
Raises
130+
------
131+
RuntimeError
132+
If the git command exits with a non-zero status.
133+
"""
134+
proc = await asyncio.create_subprocess_exec(
135+
*args,
136+
stdout=asyncio.subprocess.PIPE,
137+
stderr=asyncio.subprocess.PIPE,
138+
)
139+
stdout, stderr = await proc.communicate()
140+
if proc.returncode != 0:
141+
error_message = stderr.decode().strip()
142+
raise RuntimeError(f"Git command failed: {' '.join(args)}\nError: {error_message}")
143+
144+
return stdout, stderr

0 commit comments

Comments
 (0)