Skip to content

Commit a5fd852

Browse files
committed
Initial commit
1 parent b47bfce commit a5fd852

File tree

8 files changed

+273
-2
lines changed

8 files changed

+273
-2
lines changed

.editorconfig

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# editorconfig.org
2+
root = true
3+
4+
[*]
5+
indent_style = space
6+
indent_size = 4
7+
end_of_line = lf
8+
insert_final_newline = true
9+
charset = utf-8
10+
trim_trailing_whitespace = true

README.md

+44-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,44 @@
1-
# octodir
2-
Tool for download directorys from GitHub repository
1+
<div align="center">
2+
<img src="logo.png">
3+
</div>
4+
5+
Tool to download complete directories from a Github repository.
6+
7+
# Installation
8+
9+
```
10+
$ git clone https://github.com/Jalkhov/Octodir.git
11+
$ cd Octodir
12+
$ pip3 setup.py install
13+
```
14+
15+
# Use
16+
17+
## From the console
18+
19+
```
20+
$ octodir
21+
```
22+
23+
**You will be asked for the following data:**
24+
25+
* **Full folder url:** Direct url to the target folder
26+
* **Example:** https://github.com/Jalkhov/octodir/tree/stable/octodir
27+
* **Output folder**: Absolute path of the output directory
28+
* You can enter a dot to download in the current working directory
29+
30+
## In code
31+
32+
```python
33+
from octodir import Octodir
34+
35+
target = 'https://github.com/Jalkhov/Octodir/tree/stable/octodir'
36+
folder = '.' # Current working directory
37+
38+
Octo = Octodir(target, folder)
39+
Octo.dowload_folder()
40+
```
41+
42+
# Support me <3
43+
44+
<a href="https://www.buymeacoffee.com/Jalkhov" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-red.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>

logo.png

6.66 KB
Loading

octodir/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .octodir_core import Octodir
2+
3+
__version__ = '0.1'

octodir/octodir_cli.py

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import click
2+
from octodir import Octodir
3+
4+
5+
@click.command()
6+
@click.option("--folder_url", prompt="Full folder url", help="Full url from the folder to download")
7+
@click.option("--output_folder", prompt="Output folder", help="Folder where files will be downloaded")
8+
def octodir_cli(folder_url, output_folder):
9+
x = Octodir(folder_url, output_folder)
10+
x.dowload_folder()
11+
12+
13+
if __name__ == '__main__':
14+
octodir_cli()

octodir/octodir_core.py

+147
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
import json
2+
import os
3+
import urllib.request
4+
5+
import requests
6+
from tqdm import tqdm
7+
8+
9+
class repo_info:
10+
repo = None
11+
target_dir = None
12+
branch = None
13+
14+
15+
class api_urls:
16+
recursive = "https://api.github.com/repos/{}/git/trees/{}?recursive=1"
17+
no_recursive = "https://api.github.com/repos/{}/git/trees/{}"
18+
19+
20+
class OctodirException(Exception):
21+
pass
22+
23+
24+
def mkdirs(path):
25+
if not os.path.isdir(path):
26+
os.makedirs(path)
27+
28+
29+
class Octodir(object):
30+
31+
def __init__(self, folder_url, output_folder):
32+
super(Octodir, self).__init__()
33+
self.folder_url = folder_url
34+
self.output_folder = output_folder
35+
36+
self.repo = None
37+
self.target_dir = None
38+
self.branch = None
39+
40+
def __get_raw_url(self, file_path, url):
41+
tmp_url = url.replace(
42+
'https://api.github.com/repos/',
43+
'https://raw.githubusercontent.com/')
44+
tmp_url = tmp_url.split('/git/blobs/')[0]
45+
tmp_url = tmp_url + '/' + self.branch + '/' + file_path
46+
47+
return tmp_url
48+
49+
def __get_repo_tree(self):
50+
api = requests.get(
51+
api_urls.recursive.format(self.repo, self.branch)).text
52+
files = json.loads(api)
53+
54+
output = []
55+
location = dict()
56+
for (k, i) in enumerate(files['tree']):
57+
# If the target dir is in file path, that file
58+
# is inside target folder
59+
if self.target_dir in i['path']:
60+
if i['type'] == 'blob':
61+
tmp = [i['path']]
62+
tmp += [self.__get_raw_url(tmp[0], i['url'])]
63+
output.append(tmp)
64+
else:
65+
location[i['path']] = k
66+
files = output
67+
location = location
68+
69+
return (files, location)
70+
71+
def __scrutinize_url(self, folder_url):
72+
try:
73+
cutted_url = folder_url.replace('https://github.com/', '')
74+
splitted_url = cutted_url.split('/')
75+
76+
owner = splitted_url[0]
77+
repo = splitted_url[1]
78+
branch = splitted_url[3]
79+
80+
target_dir = [item for item in splitted_url[4:]]
81+
82+
repo_data = repo_info()
83+
repo_data.repo = owner + '/' + repo
84+
repo_data.branch = branch
85+
repo_data.target_dir = "/".join(target_dir)
86+
87+
return repo_data
88+
except IndexError:
89+
raise IndexError('Invalid repo url')
90+
91+
def __api_response(self):
92+
repo_data = self.__scrutinize_url(self.folder_url)
93+
api = requests.get(api_urls.no_recursive.format(
94+
repo_data.repo, repo_data.branch)).text
95+
response = json.loads(api)
96+
97+
return response
98+
99+
def __check_valid_output(self):
100+
if os.path.isdir(self.output_folder):
101+
return True
102+
else:
103+
raise OctodirException('Invalid output directory')
104+
105+
def __download(self, target_folder='*', recursive=True):
106+
data = self.__get_repo_tree()
107+
files = data[0]
108+
location = data[1]
109+
110+
# mkdirs(".")
111+
112+
if target_folder == '*':
113+
start = 0
114+
else:
115+
tmp_target = target_folder.replace('./', '')
116+
tmp_target = tmp_target.replace('../', '')
117+
118+
# Remove "/"
119+
tmp_target = (tmp_target if tmp_target[-1] != '/'
120+
else tmp_target[:-1])
121+
start = location[target_folder]
122+
123+
with tqdm(total=len(files), desc="Downloading folder...") as pbar:
124+
for i in files[start:]:
125+
126+
ndir = i[0].replace(
127+
self.target_dir, self.target_dir.split('/')[-1:][0])
128+
if recursive or ndir.split(target_folder)[1].count('/') \
129+
<= 1:
130+
131+
# Check output dir variable
132+
mkdirs(os.path.join(self.output_folder, os.path.dirname(ndir)))
133+
urllib.request.urlretrieve(
134+
i[1], os.path.join(self.output_folder, ndir))
135+
pbar.update(1)
136+
137+
def dowload_folder(self):
138+
check_repo = self.__api_response()
139+
if 'message' in check_repo:
140+
raise OctodirException(check_repo['message'])
141+
else:
142+
if self.__check_valid_output() is True:
143+
scrutinized_url = self.__scrutinize_url(self.folder_url)
144+
self.repo = scrutinized_url.repo
145+
self.target_dir = scrutinized_url.target_dir
146+
self.branch = scrutinized_url.branch
147+
self.__download()

requirements.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
tqdm==4.54.0
2+
requests==2.25.1
3+
click==8.0.0

setup.py

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import os
2+
import sys
3+
4+
from octodir import __version__
5+
from setuptools import setup
6+
7+
here = os.path.abspath(os.path.dirname(__file__))
8+
9+
if sys.argv[-1] == "publish":
10+
os.system("python setup.py sdist")
11+
os.system("twine upload dist/* --skip-existing")
12+
sys.exit()
13+
14+
with open(os.path.join(here, "README.md"), encoding="utf-8") as f:
15+
long_description = f.read()
16+
setup(
17+
name="Octodir",
18+
version=__version__,
19+
description="Tool for download directorys from GitHub repository",
20+
long_description=long_description,
21+
long_description_content_type="text/markdown",
22+
url="https://github.com/Jalkhov/octodir",
23+
author="Pedro Torcatt",
24+
author_email="[email protected]",
25+
classifiers=[
26+
# How mature is this project? Common values are
27+
# 3 - Alpha
28+
# 4 - Beta
29+
# 5 - Production/Stable
30+
"Development Status :: 4 - Beta",
31+
"Programming Language :: Python :: 3",
32+
"Natural Language :: English",
33+
"Environment :: Console",
34+
"License :: OSI Approved :: MIT License",
35+
36+
],
37+
keywords="github directory download",
38+
packages=["octodir"],
39+
include_package_data=True,
40+
python_requires=">=3.0",
41+
install_requires=open(
42+
os.path.join(here, "requirements.txt"), encoding="utf-8"
43+
)
44+
.read()
45+
.split("\n"),
46+
project_urls={
47+
"Bug Reports": "https://github.com/Jalkhov/octodir/issues",
48+
"Source": "https://github.com/Jalkhov/octodir/",
49+
},
50+
entry_points={"console_scripts": [
51+
"octodir=octodir.octodir_cli:octodir_cli"]},
52+
)

0 commit comments

Comments
 (0)