githubtakeout 0.1.10__tar.gz → 0.1.11__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: githubtakeout
3
- Version: 0.1.10
3
+ Version: 0.1.11
4
4
  Summary: Archive public Git Repos and Gists from GitHub
5
5
  Author: Corey Goldberg
6
6
  Maintainer: Corey Goldberg
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "githubtakeout"
7
- version = "0.1.10"
7
+ version = "0.1.11"
8
8
  description = "Archive public Git Repos and Gists from GitHub"
9
9
  license = "MIT"
10
10
  license-files = ["LICENSE"]
@@ -39,18 +39,24 @@ download = "https://pypi.org/project/githubtakeout"
39
39
  package-dir = {"" = "src"}
40
40
 
41
41
  [tool.black]
42
- line-length = 88
42
+ line-length = 120
43
43
  target-version = ["py39", "py310", "py311", "py312", "py313"]
44
44
 
45
45
  [tool.ruff]
46
- line-length = 88
46
+ line-length = 120
47
47
  respect-gitignore = true
48
48
  target-version = "py312"
49
49
 
50
50
  [tool.ruff.lint]
51
- extend-select = ["E4", "E7", "E9", "F", "I", "E501", "RUF022"]
51
+ select = [
52
+ "D", "E", "F", "I", "PT", "RUF", "TID", "W"
53
+ ]
54
+ extend-ignore = [
55
+ "D100", "D101", "D102", "D103", "D104", "D105", "D106", "D107", "D203",
56
+ "D205", "D211", "D213", "D400", "D401", "RUF012"
57
+ ]
52
58
  fixable = ["ALL"]
53
59
 
54
60
  [tool.ruff.format]
55
61
  docstring-code-format = true
56
- docstring-code-line-length = 88
62
+ docstring-code-line-length = 120
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: githubtakeout
3
- Version: 0.1.10
3
+ Version: 0.1.11
4
4
  Summary: Archive public Git Repos and Gists from GitHub
5
5
  Author: Corey Goldberg
6
6
  Maintainer: Corey Goldberg
@@ -1,7 +1,7 @@
1
- # Corey Goldberg, 2025
1
+ # Copyright (c) 2015-2025 Corey Goldberg
2
2
  # License: MIT
3
3
 
4
- """Archive Git Repos and Gists from GitHub"""
4
+ """Archive Git Repos and Gists from GitHub."""
5
5
 
6
6
  import argparse
7
7
  import getpass
@@ -32,7 +32,7 @@ def convert_size(size_bytes):
32
32
  if size_bytes == 0:
33
33
  return "0 B"
34
34
  size_name = ("B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB")
35
- i = int(math.floor(math.log(size_bytes, 1024)))
35
+ i = math.floor(math.log(size_bytes, 1024))
36
36
  p = math.pow(1024, i)
37
37
  s = round(size_bytes / p, 2)
38
38
  return f"{s} {size_name[i]}"
@@ -101,9 +101,7 @@ def clone(repo_url, local_repo_dir, include_history):
101
101
  pass
102
102
 
103
103
 
104
- def clone_and_archive_repo(
105
- repo_url, local_repo_dir, archive_format, include_history, is_gist=False
106
- ):
104
+ def clone_and_archive_repo(repo_url, local_repo_dir, archive_format, include_history, is_gist=False):
107
105
  def remove_readonly(func, path, _):
108
106
  # This is necessary so rmtree() doesn't fail if there are any readonly
109
107
  # dirs/files when trying to delete. This seems to happen after cloning on
@@ -147,32 +145,12 @@ def clone_and_archive_repo(
147
145
  logger.info(f"successfully backed up '{base_name}' repo in {elapsed:.3f} secs\n")
148
146
 
149
147
 
150
- def get_user(username, prompt_token):
151
- if prompt_token:
152
- token = getpass.getpass("Token:")
153
- if not token:
154
- sys.exit("error: auth token cannot be empty")
148
+ def get_repos(username, token, include_gists):
149
+ if token is not None:
150
+ # you need to be authenticated and then call the API
151
+ # with no username to get public and private repos
155
152
  auth = github.Auth.Token(token)
156
153
  gh = github.Github(auth=auth)
157
- else:
158
- token = os.getenv("GITHUB_TOKEN")
159
- if token is not None:
160
- auth = github.Auth.Token(token)
161
- gh = github.Github(auth=auth)
162
- else:
163
- gh = github.Github()
164
- if token is None:
165
- try:
166
- user = gh.get_user(username)
167
- except github.GithubException as e:
168
- if e.data["status"] == "404":
169
- sys.exit(f"error: user '{username}' not found")
170
- else:
171
- raise e
172
- repos = user.get_repos()
173
- else:
174
- # you need to be authenticated and then call the API
175
- # with no username to get private repos
176
154
  user = gh.get_user()
177
155
  repos = user.get_repos(affiliation="owner")
178
156
  try:
@@ -183,8 +161,31 @@ def get_user(username, prompt_token):
183
161
  sys.exit(f"error: invalid auth token for user '{username}'")
184
162
  else:
185
163
  raise e
186
- gists = user.get_gists()
187
- return user, repos, gists, token
164
+ else:
165
+ gh = github.Github()
166
+ try:
167
+ user = gh.get_user(username)
168
+ except github.GithubException as e:
169
+ if e.data["status"] == "404":
170
+ sys.exit(f"error: user '{username}' not found")
171
+ else:
172
+ raise e
173
+ repos = user.get_repos()
174
+ if include_gists:
175
+ gists = user.get_gists()
176
+ else:
177
+ gists = None
178
+ return repos, gists
179
+
180
+
181
+ def get_token(prompt_for_token):
182
+ if prompt_for_token:
183
+ token = getpass.getpass("Token:")
184
+ if not token:
185
+ sys.exit("error: auth token cannot be empty")
186
+ else:
187
+ token = os.getenv("GITHUB_TOKEN")
188
+ return token
188
189
 
189
190
 
190
191
  def run(
@@ -194,10 +195,11 @@ def run(
194
195
  include_gists,
195
196
  include_history,
196
197
  list_only,
197
- prompt_token,
198
+ prompt_for_token,
198
199
  ):
199
200
  working_dir = os.path.join(base_dir, "backups")
200
- user, repos, gists, token = get_user(username, prompt_token)
201
+ token = get_token(prompt_for_token)
202
+ repos, gists = get_repos(username, token, include_gists)
201
203
  num_repos = repos.totalCount
202
204
  if not list_only:
203
205
  logger.info(f"creating archives in: {working_dir}\n")
@@ -209,7 +211,7 @@ def run(
209
211
  logger.info(url)
210
212
  else:
211
213
  clone_and_archive_repo(url, local_repo_dir, archive_format, include_history)
212
- if include_gists:
214
+ if gists is not None:
213
215
  num_gists = gists.totalCount
214
216
  logger.info("")
215
217
  logger.info(f"found {num_gists} gists for user '{username}'\n")
@@ -219,9 +221,7 @@ def run(
219
221
  if list_only:
220
222
  logger.info(url)
221
223
  else:
222
- clone_and_archive_repo(
223
- url, local_repo_dir, archive_format, include_history, is_gist=True
224
- )
224
+ clone_and_archive_repo(url, local_repo_dir, archive_format, include_history, is_gist=True)
225
225
 
226
226
 
227
227
  def main():
@@ -240,21 +240,15 @@ def main():
240
240
  default="zip",
241
241
  help="archive format (default: %(default)s)",
242
242
  )
243
- parser.add_argument(
244
- "--gists", action="store_true", default=False, help="include gists"
245
- )
243
+ parser.add_argument("--gists", action="store_true", default=False, help="include gists")
246
244
  parser.add_argument(
247
245
  "--history",
248
246
  action="store_true",
249
247
  default=False,
250
248
  help="include commit history and branches (.git directory)",
251
249
  )
252
- parser.add_argument(
253
- "--list", action="store_true", default=False, help="list repos only"
254
- )
255
- parser.add_argument(
256
- "--token", action="store_true", default=False, help="prompt for auth token"
257
- )
250
+ parser.add_argument("--list", action="store_true", default=False, help="list repos only")
251
+ parser.add_argument("--token", action="store_true", default=False, help="prompt for auth token")
258
252
  args = parser.parse_args()
259
253
  try:
260
254
  run(
@@ -264,7 +258,7 @@ def main():
264
258
  include_gists=args.gists,
265
259
  include_history=args.history,
266
260
  list_only=args.list,
267
- prompt_token=args.token,
261
+ prompt_for_token=args.token,
268
262
  )
269
263
  except KeyboardInterrupt:
270
264
  sys.exit("\nexiting program ...")
@@ -1,8 +1,12 @@
1
+ # Copyright (c) 2025 Corey Goldberg
2
+ # License: MIT
3
+ # adapted from: https://stackoverflow.com/a/71285627/16148
4
+
5
+ """Progress bar for cloning Git repos."""
6
+
1
7
  import git
2
8
  from rich import console, progress
3
9
 
4
- # adapted from: https://stackoverflow.com/a/71285627/16148
5
-
6
10
 
7
11
  class GitProgress(git.RemoteProgress):
8
12
  OP_CODES = [
@@ -16,9 +20,7 @@ class GitProgress(git.RemoteProgress):
16
20
  "RESOLVING",
17
21
  "WRITING",
18
22
  ]
19
- OP_CODE_MAP = {
20
- getattr(git.RemoteProgress, _op_code): _op_code for _op_code in OP_CODES
21
- }
23
+ OP_CODE_MAP = {getattr(git.RemoteProgress, _op_code): _op_code for _op_code in OP_CODES}
22
24
 
23
25
  def __init__(self):
24
26
  super().__init__()
File without changes
File without changes
File without changes