Skip to content

Commit cbcce56

Browse files
authored
Merge pull request #22 from InnoFang/dev
✨ 🎨 pref: merge dev
2 parents 75c7638 + 3d06904 commit cbcce56

File tree

10 files changed

+879
-281
lines changed

10 files changed

+879
-281
lines changed

code_counter/__main__.py

+35-21
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,54 @@
11
#!/usr/bin/env python3
22
# -*- coding: utf-8 -*-
3-
4-
import time
3+
import os
4+
from code_counter.conf.config import Config
55
from code_counter.core.counter import CodeCounter
66
from code_counter.core.args import CodeCounterArgs
7-
from code_counter.conf.config import Config
7+
8+
9+
def handle_config_command(config, args):
10+
# Handle configuration command
11+
config.invoke(args.config())
12+
13+
14+
def handle_remote_args(config, cocnt_args):
15+
# Handle remote repository-related arguments
16+
args = cocnt_args.remote()
17+
if cocnt_args.is_gitee_repo() and not config.access_tokens.gitee:
18+
config.request_gitee_access_token()
19+
elif cocnt_args.is_github_repo() and not config.access_tokens.github:
20+
config.request_github_access_token()
21+
return args
22+
23+
24+
def handle_search_args(config, cocnt_args):
25+
# Handle search-related arguments
26+
args = cocnt_args.search()
27+
return args
828

929

1030
def main():
1131
cocnt_args = CodeCounterArgs()
12-
1332
config = Config()
33+
34+
# If configuration command is present, invoke and return
1435
if cocnt_args.has_config_args():
15-
config.invoke(cocnt_args.config())
36+
handle_config_command(config, cocnt_args)
1637
return
1738

18-
code_counter = CodeCounter()
19-
20-
if cocnt_args.has_search_args():
21-
args = cocnt_args.search()
22-
elif cocnt_args.has_remote_args():
23-
args = cocnt_args.remote()
24-
if cocnt_args.is_gitee_repo() and not config.access_tokens.gitee:
25-
config.request_gitee_access_token()
26-
elif cocnt_args.is_github_repo() and not config.access_tokens.github:
27-
config.request_github_access_token()
39+
# If searching or processing a remote repository, check and request access tokens
40+
if cocnt_args.has_remote_args():
41+
args = handle_remote_args(config, cocnt_args)
42+
elif cocnt_args.has_search_args():
43+
args = handle_search_args(config, cocnt_args)
2844
else:
29-
raise Exception('wrong command')
30-
31-
code_counter.setArgs(args)
45+
raise Exception('Wrong command')
3246

33-
time_start = time.time()
47+
code_counter = CodeCounter(args)
3448
code_counter.search()
35-
time_end = time.time()
3649

37-
print('\n\tTotally cost {} s.'.format(time_end - time_start))
50+
if args.output_path:
51+
print(f'Output saved to: {os.path.abspath(args.output_path)}')
3852

3953
if args.graph:
4054
code_counter.visualize()

code_counter/core/args.py

+190-41
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,76 @@
11
#!/usr/bin/env python3
22
# -*- coding: utf-8 -*-
3+
"""
4+
Command-line interface (CLI) utility for counting code lines and displaying detailed results.
5+
"""
36

47
import re
58
import sys
69
import argparse
10+
from typing import List, Optional
711
from code_counter import __version__
812

913

10-
def split_args(args):
14+
def split_args(args: str) -> List[str]:
15+
"""
16+
Split input arguments separated by commas.
17+
18+
Parameters
19+
----------
20+
args: str
21+
Input arguments as a comma-separated string.
22+
23+
Returns
24+
-------
25+
List[str]
26+
List of split arguments.
27+
"""
1128
return list(args.split(','))
1229

1330

14-
def remote_repo_parse(repo):
31+
def parse_remote_repo(repo: str) -> str:
32+
"""
33+
Parse the input repository link to extract information and construct API URL.
34+
35+
Parameters
36+
----------
37+
repo: str
38+
Input repository link.
39+
40+
Returns
41+
-------
42+
str
43+
Constructed API URL for the repository.
44+
"""
45+
# Check both HTTPS and SSH links for GitHub or Gitee repositories
46+
res = re.search(r"^(https|git)@(github|gitee).com:([^/]+)/([^\.]+)\.git$", repo, re.I)
47+
if not res:
48+
print('Remote repository link parse error! Please enter a valid HTTPS or SSH link:')
49+
print('\tcocnt remote', repo)
50+
exit(1)
51+
52+
# Construct API URL based on the matched repository
53+
api_url = f'https://{res.group(2)}.com/api/v5/repos/{res.group(3)}/{res.group(4)}/contents/'
54+
return api_url
55+
56+
57+
@PendingDeprecationWarning
58+
def remote_repo_parse(repo: str) -> str:
59+
"""
60+
Parse the input repository link and return the corresponding API URL.
61+
62+
This function is deprecated in favor of `parse_remote_repo`.
63+
64+
Parameters
65+
----------
66+
repo: str
67+
Input repository link.
68+
69+
Returns
70+
-------
71+
str
72+
Constructed API URL for the repository.
73+
"""
1574
# check HTTPS link first
1675
res = re.search(r"^https://(github|gitee).com/([^/]+)/([^\.]+)\.git$", repo, re.I)
1776
# if got none, then check SSH link
@@ -34,15 +93,17 @@ def remote_repo_parse(repo):
3493

3594

3695
class CodeCounterArgs:
37-
__SEARCH__ = 'search'
38-
__CONFIG__ = 'config'
39-
__REMOTE__ = 'remote'
96+
SEARCH = 'search'
97+
CONFIG = 'config'
98+
REMOTE = 'remote'
4099

41100
def __init__(self):
101+
"""
102+
Initialize CodeCounterArgs instance.
103+
"""
42104
parser = argparse.ArgumentParser(
43105
prog="code-counter",
44-
description="A command-line interface (CLI) utility "
45-
"that can help you easily count code and display detailed results.",
106+
description="A command-line interface (CLI) utility that counts code lines and displays detailed results.",
46107
usage="""cocnt <command> [<args>]
47108
These are common Code-Counter commands used in various situations:
48109
search Search and count code lines for the given path(s)
@@ -53,54 +114,126 @@ def __init__(self):
53114
version='%(prog)s {}'.format(__version__))
54115
parser.add_argument("command", help="Subcommand to run, `search` or `config`")
55116
args = parser.parse_args(sys.argv[1:2])
117+
56118
if not hasattr(self, args.command):
57119
print("Unrecognized command")
58120
parser.print_help()
59121
exit(1)
122+
60123
self.__args = {args.command: argparse.Namespace()}
61124
getattr(self, args.command)()
62125

63-
def has_search_args(self):
64-
return self.__SEARCH__ in self.__args
126+
def has_search_args(self) -> bool:
127+
"""
128+
Check if the instance has search-related arguments.
65129
66-
def has_remote_args(self):
67-
return self.__REMOTE__ in self.__args
130+
Returns
131+
-------
132+
bool
133+
True if search-related arguments are present, False otherwise.
134+
"""
135+
return self.SEARCH in self.__args
68136

69-
def has_config_args(self):
70-
return self.__CONFIG__ in self.__args
137+
def has_remote_args(self) -> bool:
138+
"""
139+
Check if the instance has remote-related arguments.
71140
72-
def is_github_repo(self):
73-
if not self.has_remote_args():
74-
return False
75-
return self.__args[self.__REMOTE__].input_path.startswith('https://api.github.com/repos/')
141+
Returns
142+
-------
143+
bool
144+
True if remote-related arguments are present, False otherwise.
145+
"""
146+
return self.REMOTE in self.__args
76147

77-
def is_gitee_repo(self):
78-
if not self.has_remote_args():
79-
return False
80-
return self.__args[self.__REMOTE__].input_path.startswith('https://gitee.com/api/v5/repos/')
148+
def has_config_args(self) -> bool:
149+
"""
150+
Check if the instance has config-related arguments.
151+
152+
Returns
153+
-------
154+
bool
155+
True if config-related arguments are present, False otherwise.
156+
"""
157+
return self.CONFIG in self.__args
158+
159+
def is_github_repo(self) -> bool:
160+
"""
161+
Check if the provided input is a GitHub repository.
162+
163+
Returns
164+
-------
165+
bool
166+
True if the input is a GitHub repository, False otherwise.
167+
"""
168+
return self.has_remote_args() \
169+
and self.__args[self.REMOTE].input_path.startswith('https://api.github.com/repos/')
170+
171+
def is_gitee_repo(self) -> bool:
172+
"""
173+
Check if the provided input is a Gitee repository.
81174
82-
def search(self):
175+
Returns
176+
-------
177+
bool
178+
True if the input is a Gitee repository, False otherwise.
179+
"""
180+
return self.has_remote_args() \
181+
and self.__args[self.REMOTE].input_path.startswith('https://gitee.com/api/v5/repos/')
182+
183+
def search(self) -> Optional[argparse.Namespace]:
184+
"""
185+
Get search-related arguments.
186+
187+
Returns
188+
-------
189+
Optional[argparse.Namespace]
190+
Search-related arguments if present, None otherwise.
191+
"""
83192
if not self.has_search_args():
84193
return None
85-
if self.__args[self.__SEARCH__] == argparse.Namespace():
86-
self.__args[self.__SEARCH__] = self.__search()
87-
return self.__args[self.__SEARCH__]
194+
if self.__args[self.SEARCH] == argparse.Namespace():
195+
self.__args[self.SEARCH] = self.__search()
196+
return self.__args[self.SEARCH]
88197

89-
def remote(self):
198+
def remote(self) -> Optional[argparse.Namespace]:
199+
"""
200+
Get remote-related arguments.
201+
202+
Returns
203+
-------
204+
Optional[argparse.Namespace]
205+
Remote-related arguments if present, None otherwise.
206+
"""
90207
if not self.has_remote_args():
91208
return None
92-
if self.__args[self.__REMOTE__] == argparse.Namespace():
93-
self.__args[self.__REMOTE__] = self.__remote()
94-
return self.__args[self.__REMOTE__]
209+
if self.__args[self.REMOTE] == argparse.Namespace():
210+
self.__args[self.REMOTE] = self.__remote()
211+
return self.__args[self.REMOTE]
212+
213+
def config(self) -> Optional[argparse.Namespace]:
214+
"""
215+
Get config-related arguments.
95216
96-
def config(self):
217+
Returns
218+
-------
219+
Optional[argparse.Namespace]
220+
Config-related arguments if present, None otherwise.
221+
"""
97222
if not self.has_config_args():
98223
return None
99-
if self.__args[self.__CONFIG__] == argparse.Namespace():
100-
self.__args[self.__CONFIG__] = self.__config()
101-
return self.__args[self.__CONFIG__]
224+
if self.__args[self.CONFIG] == argparse.Namespace():
225+
self.__args[self.CONFIG] = self.__config()
226+
return self.__args[self.CONFIG]
102227

103-
def __search(self):
228+
def __search(self) -> argparse.Namespace:
229+
"""
230+
Parse search-related arguments.
231+
232+
Returns
233+
-------
234+
argparse.Namespace
235+
Search-related arguments.
236+
"""
104237
parser = argparse.ArgumentParser(
105238
description="Search and count code lines for the given path(s)",
106239
usage="cocnt search input_path [-h] [-v] [-g] "
@@ -110,7 +243,7 @@ def __search(self):
110243
parser.add_argument('-v', '--verbose', dest="verbose", action='store_true',
111244
help="show verbose information")
112245
parser.add_argument('-g', '--graph', dest='graph', action='store_true',
113-
help="choose to whether to visualize the result")
246+
help="choose whether to visualize the result")
114247
parser.add_argument('-o', '--output', dest='output_path',
115248
help="specify an output path if you want to store the result")
116249
parser.add_argument('--suffix', dest='suffix', type=split_args,
@@ -121,17 +254,25 @@ def __search(self):
121254
help="ignore some directories or files that you don't want to count")
122255
return parser.parse_args(sys.argv[2:])
123256

124-
def __remote(self):
257+
def __remote(self) -> argparse.Namespace:
258+
"""
259+
Parse remote-related arguments.
260+
261+
Returns
262+
-------
263+
argparse.Namespace
264+
Remote-related arguments.
265+
"""
125266
parser = argparse.ArgumentParser(
126-
description="Search and count the remote repository with a given Github or Gitee HTTP link",
267+
description="Search and count the remote repository with a given GitHub or Gitee HTTP link",
127268
usage="cocnt remote <repository> [-h] [-v] [-g] "
128269
"[-o OUTPUT_PATH] [--suffix SUFFIX] [--comment COMMENT] [--ignore IGNORE]")
129-
parser.add_argument('input_path', metavar="repository", type=remote_repo_parse,
270+
parser.add_argument('input_path', metavar="repository", type=parse_remote_repo,
130271
help="search and count a remote repository")
131272
parser.add_argument('-v', '--verbose', dest="verbose", action='store_true',
132273
help="show verbose information")
133274
parser.add_argument('-g', '--graph', dest='graph', action='store_true',
134-
help="choose to whether to visualize the result")
275+
help="choose whether to visualize the result")
135276
parser.add_argument('-o', '--output', dest='output_path',
136277
help="specify an output path if you want to store the result")
137278
parser.add_argument('--suffix', dest='suffix', type=split_args,
@@ -142,7 +283,15 @@ def __remote(self):
142283
help="ignore some directories or files that you don't want to count")
143284
return parser.parse_args(sys.argv[2:])
144285

145-
def __config(self):
286+
def __config(self) -> argparse.Namespace:
287+
"""
288+
Parse config-related arguments.
289+
290+
Returns
291+
-------
292+
argparse.Namespace
293+
Config-related arguments.
294+
"""
146295
parser = argparse.ArgumentParser(
147296
prog="code-counter",
148297
description="configure code-counter",
@@ -178,7 +327,7 @@ def __config(self):
178327
help="delete some values of the 'ignore' in the config")
179328

180329
parser.add_argument('--github-token', dest='github_token',
181-
help="update the Github access token")
330+
help="update the GitHub access token")
182331
parser.add_argument('--gitee-token', dest='gitee_token',
183332
help="update the Gitee access token")
184333

0 commit comments

Comments
 (0)