Compare commits
3 Commits
cbcd90732d
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a4fb621ad | ||
|
|
1cac1d2e66 | ||
| 06d3098940 |
5
.env.example
Normal file
5
.env.example
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Copy this file to .env and fill in your actual tokens
|
||||||
|
# The .env file is gitignored and will be used for local development
|
||||||
|
|
||||||
|
PICABLE_DISCORD_TOKEN=your_discord_token_here
|
||||||
|
PICABLE_GITHUB_TOKEN=your_github_token_here
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,3 +1,7 @@
|
|||||||
**/__pycache__/
|
**/__pycache__/
|
||||||
**/*_tok
|
**/*_tok
|
||||||
**/.idea/
|
**/.idea/
|
||||||
|
|
||||||
|
# Environment variables and local development overrides
|
||||||
|
.env
|
||||||
|
docker-compose.override.yml
|
||||||
|
|||||||
14
Dockerfile
14
Dockerfile
@@ -2,16 +2,20 @@ FROM python:3.14-slim
|
|||||||
|
|
||||||
RUN set -eux; \
|
RUN set -eux; \
|
||||||
apt-get update; \
|
apt-get update; \
|
||||||
apt-get install -y --no-install-recommends cloc; \
|
apt-get install -y --no-install-recommends cloc git; \
|
||||||
apt-get dist-clean
|
apt-get clean; \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN pip install --no-cache-dir discord asyncio requests
|
RUN pip install --no-cache-dir discord.py requests
|
||||||
|
|
||||||
COPY main.py .
|
COPY main.py .
|
||||||
COPY PICable.py .
|
COPY PICable.py .
|
||||||
|
|
||||||
RUN useradd -m appuser
|
RUN useradd -m appuser && \
|
||||||
|
mkdir -p /temp && \
|
||||||
|
chown appuser:appuser /temp
|
||||||
|
|
||||||
USER appuser
|
USER appuser
|
||||||
|
|
||||||
CMD ["python", "main.py"]
|
CMD ["python", "-u", "main.py"]
|
||||||
|
|||||||
19
PICable.py
19
PICable.py
@@ -1,6 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
@@ -54,20 +53,28 @@ def get_lines_of_code(owner, repository):
|
|||||||
repository_clone_dir = os.path.expanduser(f"{parent_dir}/{repository}")
|
repository_clone_dir = os.path.expanduser(f"{parent_dir}/{repository}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
print(f"Cloning {repository_url}...")
|
||||||
subprocess.run(
|
subprocess.run(
|
||||||
["git", "clone", "--depth", "1", repository_url, repository_clone_dir],
|
["git", "clone", "--depth", "1", "--progress", repository_url, repository_clone_dir],
|
||||||
check=True,
|
check=True,
|
||||||
stdout=sys.stdout,
|
|
||||||
stderr=sys.stderr,
|
|
||||||
)
|
)
|
||||||
|
print("Clone complete. Running cloc...")
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
["cloc", f"--exclude-lang={','.join(EXCLUDED_LANGUAGES)}", repository_clone_dir],
|
["cloc", f"--exclude-lang={','.join(EXCLUDED_LANGUAGES)}", repository_clone_dir],
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
text=True,
|
text=True,
|
||||||
check=True,
|
check=True,
|
||||||
)
|
)
|
||||||
number_of_lines_of_code = int(result.stdout.split("\n")[-3].split()[-1])
|
|
||||||
except Exception:
|
# Find the SUM line and extract the last column (code lines)
|
||||||
|
for line in result.stdout.split("\n"):
|
||||||
|
if line.strip().startswith("SUM:"):
|
||||||
|
number_of_lines_of_code = int(line.split()[-1])
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise ValueError("Could not find SUM line in cloc output")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error occurred: {e}")
|
||||||
return -1
|
return -1
|
||||||
finally:
|
finally:
|
||||||
subprocess.run(["rm", "-rf", parent_dir], check=True)
|
subprocess.run(["rm", "-rf", parent_dir], check=True)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
services:
|
services:
|
||||||
picable:
|
picable:
|
||||||
build: .
|
image: didas72/picable:latest
|
||||||
container_name: picable
|
container_name: picable
|
||||||
environment:
|
environment:
|
||||||
- PICABLE_DISCORD_TOKEN=yourdiscordtoken
|
- PICABLE_DISCORD_TOKEN=${PICABLE_DISCORD_TOKEN}
|
||||||
- PICABLE_GITHUB_TOKEN=yourgithubtoken
|
- PICABLE_GITHUB_TOKEN=${PICABLE_GITHUB_TOKEN}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|||||||
10
main.py
10
main.py
@@ -11,7 +11,6 @@ MAX_STORAGE_KB = 50 * 1024 * 1024 # 50GB
|
|||||||
DISCORD_TOKEN = os.getenv("PICABLE_DISCORD_TOKEN")
|
DISCORD_TOKEN = os.getenv("PICABLE_DISCORD_TOKEN")
|
||||||
GITHUB_TOKEN = os.getenv("PICABLE_GITHUB_TOKEN")
|
GITHUB_TOKEN = os.getenv("PICABLE_GITHUB_TOKEN")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
current_storage_kb = 0
|
current_storage_kb = 0
|
||||||
storage_condition = Condition()
|
storage_condition = Condition()
|
||||||
current_repositories = set()
|
current_repositories = set()
|
||||||
@@ -24,7 +23,7 @@ if __name__ == "__main__":
|
|||||||
intents = Intents.default()
|
intents = Intents.default()
|
||||||
intents.message_content = True
|
intents.message_content = True
|
||||||
client = commands.Bot(command_prefix="/", intents=intents)
|
client = commands.Bot(command_prefix="/", intents=intents)
|
||||||
client.run(DISCORD_TOKEN)
|
|
||||||
|
|
||||||
@client.event
|
@client.event
|
||||||
async def on_ready():
|
async def on_ready():
|
||||||
@@ -36,11 +35,13 @@ if __name__ == "__main__":
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Failed to sync commands: {e}")
|
print(f"Failed to sync commands: {e}")
|
||||||
|
|
||||||
|
|
||||||
@client.tree.command(name="ping", description="Check the bot's latency.")
|
@client.tree.command(name="ping", description="Check the bot's latency.")
|
||||||
async def ping(interaction: Interaction):
|
async def ping(interaction: Interaction):
|
||||||
latency = client.latency * 1000
|
latency = client.latency * 1000
|
||||||
await interaction.response.send_message(f"Pong! Latency: {latency:.2f}ms")
|
await interaction.response.send_message(f"Pong! Latency: {latency:.2f}ms")
|
||||||
|
|
||||||
|
|
||||||
async def handle_picable(owner: str, repository: str, repository_size_kb: int, github_token: str):
|
async def handle_picable(owner: str, repository: str, repository_size_kb: int, github_token: str):
|
||||||
global current_storage_kb
|
global current_storage_kb
|
||||||
async with storage_condition:
|
async with storage_condition:
|
||||||
@@ -50,6 +51,7 @@ if __name__ == "__main__":
|
|||||||
print(f"Storage is {current_storage_kb / MAX_STORAGE_KB * 100:.2f}% full.")
|
print(f"Storage is {current_storage_kb / MAX_STORAGE_KB * 100:.2f}% full.")
|
||||||
return await to_thread(PICable, owner, repository, github_token)
|
return await to_thread(PICable, owner, repository, github_token)
|
||||||
|
|
||||||
|
|
||||||
@client.tree.command(name="picable", description="Check if a Github repository is eligible for PIC.")
|
@client.tree.command(name="picable", description="Check if a Github repository is eligible for PIC.")
|
||||||
@app_commands.describe(owner="The owner of the repository", repository="The name of the repository")
|
@app_commands.describe(owner="The owner of the repository", repository="The name of the repository")
|
||||||
async def picable(interaction: Interaction, owner: str, repository: str):
|
async def picable(interaction: Interaction, owner: str, repository: str):
|
||||||
@@ -108,3 +110,7 @@ if __name__ == "__main__":
|
|||||||
async with storage_condition:
|
async with storage_condition:
|
||||||
current_storage_kb -= repository_size_kb
|
current_storage_kb -= repository_size_kb
|
||||||
storage_condition.notify_all()
|
storage_condition.notify_all()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
client.run(DISCORD_TOKEN)
|
||||||
|
|||||||
Reference in New Issue
Block a user