1
+ //! Git repository inspector.
2
+ //!
3
+ //! This module provides functionality to extract the GitHub repository
4
+ //! owner and name from the local `.git/config` file.
5
+ //!
6
+ //! If the program is not running inside a Git repository, it supports falling
7
+ //! back to parsing command-line arguments for owner and repo name.
8
+ use regex:: Regex ;
9
+ use std:: { env, fs, process:: exit} ;
10
+ use std:: process:: Command ;
11
+
12
+ /// Attempts to determine the repository owner and name.
13
+ ///
14
+ /// This function will first check if the current working directory is inside a Git
15
+ /// repository using `git rev-parse --is-inside-work-tree`. If so, it reads the
16
+ /// `.git/config` file and parses the `url` entry for the `origin` remote to extract
17
+ /// the GitHub owner and repository name.
18
+ ///
19
+ /// If the directory is not inside a Git repo, this function falls back to expecting
20
+ /// two arguments: the repository owner at position 1 and the repository name at position 2.
21
+ ///
22
+ /// # Arguments
23
+ ///
24
+ /// * `args` - A vector of command-line arguments. Only used if not in a Git repo.
25
+ ///
26
+ /// # Returns
27
+ ///
28
+ /// A tuple `(owner, repo)` as `String` values.
29
+ ///
30
+ /// # Panics / Exits
31
+ ///
32
+ /// This function will terminate the program with an error message if:
33
+ /// - The Git command fails or indicates it's not inside a repo
34
+ /// - The `.git/config` file cannot be read or parsed
35
+ /// - Not enough CLI arguments are provided when required
36
+ pub async fn get_repo_path ( args : Vec < String > ) -> ( String , String ) {
37
+ let current_dir = env:: current_dir ( ) . expect ( "Unable to get current directory" ) ;
38
+ let output = Command :: new ( "git" )
39
+ . current_dir ( & current_dir)
40
+ . args ( & [ "rev-parse" , "--is-inside-work-tree" ] )
41
+ . output ( )
42
+ . expect ( "Failed to execute git command" ) ;
43
+
44
+ if output. status . success ( ) && String :: from_utf8_lossy ( & output. stdout ) . trim ( ) == "true" {
45
+ let config_path = current_dir. join ( ".git" ) . join ( "config" ) ;
46
+ if !config_path. exists ( ) {
47
+ eprintln ! ( ".git/config not found. Are you in a Git repository?" ) ;
48
+ exit ( 1 ) ;
49
+ }
50
+ let config_content = fs:: read_to_string ( config_path) . unwrap_or_else ( |e| {
51
+ eprintln ! ( "Unable to read .git/config: {}" , e) ;
52
+ exit ( 1 ) ;
53
+ } ) ;
54
+
55
+ let owner_re = Regex :: new ( r#"url\s*=\s*git@github\.com:(\w+)/([\w-]+)\.git"# ) . unwrap ( ) ;
56
+ let caps = owner_re. captures ( & config_content) . unwrap_or_else ( || {
57
+ eprintln ! ( "Failed to extract repository owner and name from .git/config" ) ;
58
+ exit ( 1 ) ;
59
+ } ) ;
60
+
61
+ let owner = caps. get ( 1 ) . unwrap ( ) . as_str ( ) . to_string ( ) ;
62
+ let name = caps. get ( 2 ) . unwrap ( ) . as_str ( ) . to_string ( ) ;
63
+ ( owner, name)
64
+ } else if args. len ( ) == 3 {
65
+ ( args[ 1 ] . clone ( ) , args[ 2 ] . clone ( ) )
66
+ } else {
67
+ eprintln ! ( "Position 1: Owner, position 2: repo name, or be in a git repo" ) ;
68
+ exit ( 1 ) ;
69
+ }
70
+ }
0 commit comments