githubtakeout 0.1.9__tar.gz → 0.1.10__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.
- {githubtakeout-0.1.9/src/githubtakeout.egg-info → githubtakeout-0.1.10}/PKG-INFO +1 -2
- {githubtakeout-0.1.9 → githubtakeout-0.1.10}/pyproject.toml +1 -2
- {githubtakeout-0.1.9 → githubtakeout-0.1.10/src/githubtakeout.egg-info}/PKG-INFO +1 -2
- {githubtakeout-0.1.9 → githubtakeout-0.1.10}/src/githubtakeout.egg-info/requires.txt +0 -1
- {githubtakeout-0.1.9 → githubtakeout-0.1.10}/src/githubtakeout.py +47 -55
- {githubtakeout-0.1.9 → githubtakeout-0.1.10}/LICENSE +0 -0
- {githubtakeout-0.1.9 → githubtakeout-0.1.10}/README.md +0 -0
- {githubtakeout-0.1.9 → githubtakeout-0.1.10}/setup.cfg +0 -0
- {githubtakeout-0.1.9 → githubtakeout-0.1.10}/src/githubtakeout.egg-info/SOURCES.txt +0 -0
- {githubtakeout-0.1.9 → githubtakeout-0.1.10}/src/githubtakeout.egg-info/dependency_links.txt +0 -0
- {githubtakeout-0.1.9 → githubtakeout-0.1.10}/src/githubtakeout.egg-info/entry_points.txt +0 -0
- {githubtakeout-0.1.9 → githubtakeout-0.1.10}/src/githubtakeout.egg-info/top_level.txt +0 -0
- {githubtakeout-0.1.9 → githubtakeout-0.1.10}/src/progress.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: githubtakeout
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.10
|
|
4
4
|
Summary: Archive public Git Repos and Gists from GitHub
|
|
5
5
|
Author: Corey Goldberg
|
|
6
6
|
Maintainer: Corey Goldberg
|
|
@@ -21,7 +21,6 @@ License-File: LICENSE
|
|
|
21
21
|
Requires-Dist: GitPython==3.1.45
|
|
22
22
|
Requires-Dist: PyGithub==2.8.1
|
|
23
23
|
Requires-Dist: rich==14.1.0
|
|
24
|
-
Requires-Dist: tenacity==9.1.2
|
|
25
24
|
Dynamic: license-file
|
|
26
25
|
|
|
27
26
|
# githubtakeout
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "githubtakeout"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.10"
|
|
8
8
|
description = "Archive public Git Repos and Gists from GitHub"
|
|
9
9
|
license = "MIT"
|
|
10
10
|
license-files = ["LICENSE"]
|
|
@@ -25,7 +25,6 @@ dependencies = [
|
|
|
25
25
|
"GitPython==3.1.45",
|
|
26
26
|
"PyGithub==2.8.1",
|
|
27
27
|
"rich==14.1.0",
|
|
28
|
-
"tenacity==9.1.2",
|
|
29
28
|
]
|
|
30
29
|
|
|
31
30
|
[project.scripts]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: githubtakeout
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.10
|
|
4
4
|
Summary: Archive public Git Repos and Gists from GitHub
|
|
5
5
|
Author: Corey Goldberg
|
|
6
6
|
Maintainer: Corey Goldberg
|
|
@@ -21,7 +21,6 @@ License-File: LICENSE
|
|
|
21
21
|
Requires-Dist: GitPython==3.1.45
|
|
22
22
|
Requires-Dist: PyGithub==2.8.1
|
|
23
23
|
Requires-Dist: rich==14.1.0
|
|
24
|
-
Requires-Dist: tenacity==9.1.2
|
|
25
24
|
Dynamic: license-file
|
|
26
25
|
|
|
27
26
|
# githubtakeout
|
|
@@ -19,7 +19,6 @@ from timeit import default_timer
|
|
|
19
19
|
|
|
20
20
|
import git
|
|
21
21
|
import github
|
|
22
|
-
from tenacity import retry, stop_after_attempt, wait_fixed
|
|
23
22
|
|
|
24
23
|
from progress import GitProgress
|
|
25
24
|
|
|
@@ -50,52 +49,6 @@ def add_creds(url, username, token):
|
|
|
50
49
|
return new_url
|
|
51
50
|
|
|
52
51
|
|
|
53
|
-
def clone_and_archive_repo(
|
|
54
|
-
repo_url, local_repo_dir, archive_format, include_history, is_gist=False
|
|
55
|
-
):
|
|
56
|
-
def remove_readonly(func, path, _):
|
|
57
|
-
# This is necessary so rmtree() doesn't fail if there are any readonly
|
|
58
|
-
# dirs/files when trying to delete. This seems to happen after cloning on
|
|
59
|
-
# Windows. When any error occurs during deletion, we change the permissions
|
|
60
|
-
# and and reattempt removal.
|
|
61
|
-
#
|
|
62
|
-
# give read permissions
|
|
63
|
-
os.chmod(path, stat.S_IREAD)
|
|
64
|
-
# give write permissions
|
|
65
|
-
os.chmod(path, stat.S_IWRITE)
|
|
66
|
-
# try again
|
|
67
|
-
func(path)
|
|
68
|
-
|
|
69
|
-
try:
|
|
70
|
-
# delete repo if it already exists
|
|
71
|
-
shutil.rmtree(local_repo_dir, onexc=remove_readonly)
|
|
72
|
-
except FileNotFoundError:
|
|
73
|
-
pass
|
|
74
|
-
repo_name = urllib.parse.urlparse(repo_url).path.lstrip("/")
|
|
75
|
-
logger.info(f"cloning repo: {repo_name} to {local_repo_dir}")
|
|
76
|
-
start = default_timer()
|
|
77
|
-
clone(repo_url, local_repo_dir, include_history)
|
|
78
|
-
if not include_history:
|
|
79
|
-
# delete the .git directory if we are not saving history
|
|
80
|
-
try:
|
|
81
|
-
git_dir = os.path.join(local_repo_dir, ".git")
|
|
82
|
-
shutil.rmtree(git_dir, onexc=remove_readonly)
|
|
83
|
-
except FileNotFoundError:
|
|
84
|
-
pass
|
|
85
|
-
archive_path = archive(local_repo_dir, archive_format, is_gist)
|
|
86
|
-
size = convert_size(os.path.getsize(archive_path))
|
|
87
|
-
logger.info(f"archive size: {size}")
|
|
88
|
-
logger.info("deleting repo")
|
|
89
|
-
try:
|
|
90
|
-
# delete repo after archive is created
|
|
91
|
-
shutil.rmtree(local_repo_dir, onexc=remove_readonly)
|
|
92
|
-
except FileNotFoundError:
|
|
93
|
-
pass
|
|
94
|
-
elapsed = default_timer() - start
|
|
95
|
-
base_name = os.path.basename(local_repo_dir)
|
|
96
|
-
logger.info(f"successfully backed up '{base_name}' repo in {elapsed:.3f} secs\n")
|
|
97
|
-
|
|
98
|
-
|
|
99
52
|
def archive(local_repo_dir, archive_format="zip", is_gist=False):
|
|
100
53
|
if archive_format not in ARCHIVE_FORMATS:
|
|
101
54
|
raise ValueError(f"{archive_format} is not a valid archive format")
|
|
@@ -119,7 +72,6 @@ def archive(local_repo_dir, archive_format="zip", is_gist=False):
|
|
|
119
72
|
return archive_path
|
|
120
73
|
|
|
121
74
|
|
|
122
|
-
@retry(stop=stop_after_attempt(5), wait=wait_fixed(2))
|
|
123
75
|
def clone(repo_url, local_repo_dir, include_history):
|
|
124
76
|
try:
|
|
125
77
|
if include_history:
|
|
@@ -149,12 +101,52 @@ def clone(repo_url, local_repo_dir, include_history):
|
|
|
149
101
|
pass
|
|
150
102
|
|
|
151
103
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
104
|
+
def clone_and_archive_repo(
|
|
105
|
+
repo_url, local_repo_dir, archive_format, include_history, is_gist=False
|
|
106
|
+
):
|
|
107
|
+
def remove_readonly(func, path, _):
|
|
108
|
+
# This is necessary so rmtree() doesn't fail if there are any readonly
|
|
109
|
+
# dirs/files when trying to delete. This seems to happen after cloning on
|
|
110
|
+
# Windows. When any error occurs during deletion, we change the permissions
|
|
111
|
+
# and and reattempt removal.
|
|
112
|
+
#
|
|
113
|
+
# give read permissions
|
|
114
|
+
os.chmod(path, stat.S_IREAD)
|
|
115
|
+
# give write permissions
|
|
116
|
+
os.chmod(path, stat.S_IWRITE)
|
|
117
|
+
# try again
|
|
118
|
+
func(path)
|
|
119
|
+
|
|
120
|
+
try:
|
|
121
|
+
# delete repo if it already exists
|
|
122
|
+
shutil.rmtree(local_repo_dir, onexc=remove_readonly)
|
|
123
|
+
except FileNotFoundError:
|
|
124
|
+
pass
|
|
125
|
+
repo_name = urllib.parse.urlparse(repo_url).path.lstrip("/")
|
|
126
|
+
logger.info(f"cloning repo: {repo_name} to {local_repo_dir}")
|
|
127
|
+
start = default_timer()
|
|
128
|
+
clone(repo_url, local_repo_dir, include_history)
|
|
129
|
+
if not include_history:
|
|
130
|
+
# delete the .git directory if we are not saving history
|
|
131
|
+
try:
|
|
132
|
+
git_dir = os.path.join(local_repo_dir, ".git")
|
|
133
|
+
shutil.rmtree(git_dir, onexc=remove_readonly)
|
|
134
|
+
except FileNotFoundError:
|
|
135
|
+
pass
|
|
136
|
+
archive_path = archive(local_repo_dir, archive_format, is_gist)
|
|
137
|
+
size = convert_size(os.path.getsize(archive_path))
|
|
138
|
+
logger.info(f"archive size: {size}")
|
|
139
|
+
logger.info("deleting repo")
|
|
140
|
+
try:
|
|
141
|
+
# delete repo after archive is created
|
|
142
|
+
shutil.rmtree(local_repo_dir, onexc=remove_readonly)
|
|
143
|
+
except FileNotFoundError:
|
|
144
|
+
pass
|
|
145
|
+
elapsed = default_timer() - start
|
|
146
|
+
base_name = os.path.basename(local_repo_dir)
|
|
147
|
+
logger.info(f"successfully backed up '{base_name}' repo in {elapsed:.3f} secs\n")
|
|
155
148
|
|
|
156
149
|
|
|
157
|
-
@retry(stop=stop_after_attempt(5), wait=wait_fixed(2))
|
|
158
150
|
def get_user(username, prompt_token):
|
|
159
151
|
if prompt_token:
|
|
160
152
|
token = getpass.getpass("Token:")
|
|
@@ -185,7 +177,7 @@ def get_user(username, prompt_token):
|
|
|
185
177
|
repos = user.get_repos(affiliation="owner")
|
|
186
178
|
try:
|
|
187
179
|
# this just makes an API request so we can exit if unauthorized
|
|
188
|
-
_ =
|
|
180
|
+
_ = repos.totalCount
|
|
189
181
|
except github.GithubException as e:
|
|
190
182
|
if e.data["status"] == "401":
|
|
191
183
|
sys.exit(f"error: invalid auth token for user '{username}'")
|
|
@@ -206,7 +198,7 @@ def run(
|
|
|
206
198
|
):
|
|
207
199
|
working_dir = os.path.join(base_dir, "backups")
|
|
208
200
|
user, repos, gists, token = get_user(username, prompt_token)
|
|
209
|
-
num_repos =
|
|
201
|
+
num_repos = repos.totalCount
|
|
210
202
|
if not list_only:
|
|
211
203
|
logger.info(f"creating archives in: {working_dir}\n")
|
|
212
204
|
logger.info(f"found {num_repos} repos for user '{username}'\n")
|
|
@@ -218,7 +210,7 @@ def run(
|
|
|
218
210
|
else:
|
|
219
211
|
clone_and_archive_repo(url, local_repo_dir, archive_format, include_history)
|
|
220
212
|
if include_gists:
|
|
221
|
-
num_gists =
|
|
213
|
+
num_gists = gists.totalCount
|
|
222
214
|
logger.info("")
|
|
223
215
|
logger.info(f"found {num_gists} gists for user '{username}'\n")
|
|
224
216
|
for gist in gists:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{githubtakeout-0.1.9 → githubtakeout-0.1.10}/src/githubtakeout.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|