Skip to content

Commit 4e5a0f4

Browse files
feat: support both 2-part and 3-part slug formats (cs50/hello and cs50/c/hello)
1 parent e73748d commit 4e5a0f4

File tree

1 file changed

+60
-11
lines changed

1 file changed

+60
-11
lines changed

bootcs/__main__.py

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,35 @@ def main():
101101
'.cxx': 'cpp',
102102
}
103103

104+
# Supported languages for slug parsing
105+
SUPPORTED_LANGUAGES = {'c', 'python', 'java', 'cpp', 'go', 'rust', 'javascript', 'typescript'}
106+
107+
108+
def parse_slug(slug: str):
109+
"""
110+
Parse a slug into course, language, and stage components.
111+
112+
Supports two formats:
113+
- 2 parts: "cs50/hello" -> (course="cs50", language=None, stage="hello")
114+
- 3 parts: "cs50/c/hello" -> (course="cs50", language="c", stage="hello")
115+
116+
Returns:
117+
tuple: (course_slug, language_from_slug, stage_slug)
118+
- language_from_slug is None if slug has 2 parts
119+
"""
120+
parts = slug.split("/")
121+
if len(parts) == 3:
122+
course_slug, lang, stage_slug = parts
123+
# Validate that middle part looks like a language
124+
if lang in SUPPORTED_LANGUAGES:
125+
return course_slug, lang, stage_slug
126+
# If middle part doesn't look like a language, treat as 2-part with nested stage
127+
return parts[0], None, "/".join(parts[1:])
128+
elif len(parts) == 2:
129+
return parts[0], None, parts[1]
130+
else:
131+
return None, None, slug
132+
104133

105134
def detect_language(directory: Path = None, explicit: str = None) -> str:
106135
"""
@@ -151,9 +180,15 @@ def run_check(args):
151180
slug = args.slug
152181
force_update = getattr(args, 'update', False)
153182

154-
# Auto-detect language from files in current directory
183+
# Parse slug to extract language if present (e.g., "cs50/c/hello")
184+
course_slug, lang_from_slug, stage_slug = parse_slug(slug)
185+
186+
# Determine language: slug > explicit flag > auto-detect
155187
explicit_lang = getattr(args, 'language', None)
156-
language = detect_language(directory=Path.cwd(), explicit=explicit_lang)
188+
if lang_from_slug:
189+
language = lang_from_slug
190+
else:
191+
language = detect_language(directory=Path.cwd(), explicit=explicit_lang)
157192

158193
# Determine check directory
159194
if args.local:
@@ -307,22 +342,30 @@ def find_check_dir(slug, language: str = "c", force_update: bool = False):
307342
"""
308343
Find the check directory for a given slug.
309344
345+
Supports two slug formats:
346+
- 2 parts: "cs50/hello" (language auto-detected or passed as parameter)
347+
- 3 parts: "cs50/c/hello" (language extracted from slug)
348+
310349
Priority:
311350
1. BOOTCS_CHECKS_PATH environment variable (for evaluator)
312351
2. Remote API download (with local cache)
313352
3. Local directories (for development)
314353
"""
315-
# Extract parts from slug (e.g., "cs50/credit" -> course="cs50", stage="credit")
316-
parts = slug.split("/")
317-
if len(parts) == 2:
318-
course_slug, stage_name = parts
319-
else:
320-
stage_name = slug
321-
course_slug = None
354+
# Use parse_slug to extract components
355+
course_slug, lang_from_slug, stage_name = parse_slug(slug)
356+
357+
# If slug contains language, use it; otherwise use provided parameter
358+
if lang_from_slug:
359+
language = lang_from_slug
322360

323361
# 1. Check environment variable first (used by evaluator)
324362
if "BOOTCS_CHECKS_PATH" in os.environ:
325363
checks_path = Path(os.environ["BOOTCS_CHECKS_PATH"])
364+
# Try with course/language/stage structure (e.g., checks/cs50/c/hello)
365+
if course_slug:
366+
path = checks_path / course_slug / language / stage_name
367+
if path.exists():
368+
return path
326369
# Try with language/stage structure (e.g., checks/c/hello)
327370
path = checks_path / language / stage_name
328371
if path.exists():
@@ -378,9 +421,15 @@ def run_submit(args):
378421

379422
slug = args.slug
380423

381-
# Auto-detect language from files in current directory
424+
# Parse slug to extract language if present (e.g., "cs50/c/hello")
425+
course_slug, lang_from_slug, stage_slug = parse_slug(slug)
426+
427+
# Determine language: slug > explicit flag > auto-detect
382428
explicit_lang = getattr(args, 'language', None)
383-
language = detect_language(directory=Path.cwd(), explicit=explicit_lang)
429+
if lang_from_slug:
430+
language = lang_from_slug
431+
else:
432+
language = detect_language(directory=Path.cwd(), explicit=explicit_lang)
384433

385434
# Check if logged in
386435
if not is_logged_in():

0 commit comments

Comments
 (0)