Created
July 7, 2018 03:41
-
-
Save Alex-duzhichao/00c4e35b505f88aa5b3a12323b69f496 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import requests | |
import lxml.html | |
import re | |
import sys | |
import os | |
import contextlib | |
import subprocess | |
class BaseError(Exception): | |
""" | |
base error exception, all error exceptions should inherent from this class. | |
""" | |
def __str__(self): | |
return '{}: {}'.format(type(self).__name__, self.args) | |
class StatusCodeError(BaseError): | |
""" | |
status code error exception. | |
""" | |
def __init__(self, msg, statusCode): | |
""" | |
init StatusCodeError | |
Args: | |
msg: described error msg | |
statusCode: error status code | |
""" | |
errmsg = '{}, status code error, code: {}'.format(msg, str(statusCode)) | |
super().__init__(errmsg) | |
class FileExistsError(BaseError): | |
""" | |
file exists error exception. | |
""" | |
def __init__(self, msg, file_name): | |
""" | |
init FileExistsError | |
Args: | |
msg: described error msg | |
file_name: file name | |
""" | |
errmsg = '{}, file exists error, file: {}'.format(msg, file_name) | |
super().__init__(errmsg) | |
class TaskNotExistsError(BaseError): | |
""" | |
task do not implemented. | |
""" | |
def __init__(self, task_name): | |
""" | |
init TaskNotExistsError | |
Args: | |
task_name: task name | |
""" | |
errmsg = 'task not exists error, task: {}'.format(task_name) | |
super().__init__(errmsg) | |
class ProgressBar(object): | |
def __init__(self, | |
title, | |
count=0.0, | |
run_status=None, | |
fin_status=None, | |
total=100.0, | |
unit='', | |
sep='/', | |
chunk_size=1.0): | |
super().__init__() | |
self.info = "[%s] %s %.2f %s %s %.2f %s" | |
self.title = title | |
self.total = total | |
self.count = count | |
self.chunk_size = chunk_size | |
self.status = run_status or "" | |
self.fin_status = fin_status or " " * len(self.status) | |
self.unit = unit | |
self.seq = sep | |
def __get_info(self): | |
# [Title]status progress unit splitor total unit | |
_info = self.info % (self.title, self.status, | |
self.count/self.chunk_size, self.unit, self.seq, self.total/self.chunk_size, self.unit) | |
return _info | |
def refresh(self, count=1, status=None): | |
self.count += count | |
# if status is not None: | |
self.status = status or self.status | |
end_str = "\r" | |
if self.count >= self.total: | |
end_str = '\n' | |
self.status = status or self.fin_status | |
print(self.__get_info(), end=end_str) | |
def CheckCall(args, **kwargs): | |
exit_message = kwargs.get('exit_message', None) | |
kwargs.pop('exit_message', None) | |
try: | |
subprocess.check_call(args, **kwargs) | |
except subprocess.CalledProcessError as error: | |
if exit_message: | |
sys.exit(exit_message) | |
sys.exit(error.returncode) | |
def readBoolChar(prompt): | |
""" | |
read a char from stdin, and return bool value | |
Args: | |
prompt: prompt | |
Returns: | |
if input char is y or Y, then return True | |
if input char is n or N, then return False | |
else loop until right char in inputed. | |
""" | |
while True: | |
print('{} [Y/y] or [N/n]: '.format(prompt), end='', flush=True) | |
ch = sys.stdin.readline() | |
ch = ch[:-1] | |
if ch == 'Y' or ch == 'y': | |
return True | |
if ch == 'N' or ch == 'n': | |
return False | |
def readNumChar(prompt, num=20): | |
""" | |
read a char from stdin, and return int value | |
Args: | |
prompt: prompt | |
num: the upper bound of input value(default is 20) | |
Returns: | |
an int value of input char | |
""" | |
while True: | |
print('{} [0 -- {}): '.format(prompt, num), end='', flush=True) | |
ch = sys.stdin.readline() | |
ch = ch[:-1] | |
if ch.isnumeric() and int(ch) < num: | |
return int(ch) | |
def getExeURLsFromPage(page): | |
""" | |
get all urls with end of *exe* from page. | |
Args: | |
page: page url to crawl | |
Return: | |
A list of urls can be downloaded | |
""" | |
response = requests.get(page) | |
if response.status_code != 200: | |
raise StatusCodeError("getExeURLsFromPage: " + page, response.status_code) | |
html = response.text | |
tree = lxml.html.fromstring(html) | |
aNodes = tree.xpath("//a") | |
exeUrlsList = [] | |
for node in aNodes: | |
url = node.get("href") | |
if url is None: | |
continue | |
if re.search("exe$", url) is not None: | |
exeUrlsList.append(url) | |
return exeUrlsList | |
def downloadURL(file_name, url): | |
""" | |
download url and save to file_name | |
Args: | |
file_name: file to write | |
url: url to download | |
""" | |
print("downloding {}".format(url)) | |
if os.path.exists(file_name): | |
raise FileExistsError("downloadURL", file_name) | |
with contextlib.closing(requests.get(url, stream = True)) as response: | |
chunk_size = 1024 | |
content_size = int(response.headers['content-length']) | |
print(chunk_size, content_size) | |
progress = ProgressBar(file_name, total = content_size, | |
unit = "KB", chunk_size = chunk_size, run_status = "downloding", | |
fin_status = "finished") | |
with open(file_name, "wb") as file: | |
for data in response.iter_content(chunk_size = chunk_size): | |
file.write(data) | |
progress.refresh(count = len(data)) | |
def installSogouPinyin(**kwargs): | |
name = kwargs.get("name") | |
page = kwargs.get("page") | |
print("installExe {} {}".format(name, page)) | |
exeUrlsList = getExeURLsFromPage(page) | |
for i in range(len(exeUrlsList)): | |
print("{}) {}\n".format(i, exeUrlsList[i]), end='') | |
index = readNumChar("input num to download", len(exeUrlsList)) | |
downloadURL(name + ".exe", exeUrlsList[index]) | |
subprocess.run("./" + name + ".exe") | |
def downloadExeAndInstall(**kwargs): | |
name = kwargs.get("name") | |
url = kwargs.get("url") | |
print("downloadExeAndInstall {} {}".format(name, url)) | |
downloadURL(name + ".exe", url) | |
bin = "./" + name + ".exe" | |
subprocess.run("./" + name + ".exe") | |
def installVimPlugin(**kwargs): | |
name = kwargs.get("name") | |
vimPlugUrl = kwargs.get("vimPlugUrl") | |
vimrcUrl = kwargs.get("vimrcUrl") | |
vimBundlesUrl = kwargs.get("vimBundlesUrl") | |
home = os.environ["USERPROFILE"] | |
vimPluginPath = os.path.join(home, ".vim") | |
vimPlugPath = os.path.join(vimPluginPath, "vim-plug", "autoload") | |
if os.path.exists(vimPluginPath) is False: | |
print("makedirs {} {} ".format(vimPluginPath, vimPlugPath)) | |
os.makedirs(vimPluginPath) | |
os.makedirs(vimPlugPath) | |
#download vim-plug | |
vimPlugFile = os.path.join(vimPlugPath, "plug.vim") | |
downloadURL(vimPlugFile, vimPlugUrl) | |
#download vimrc | |
vimrcFile = os.path.join(home, ".vimrc") | |
downloadURL(vimrcFile, vimrcUrl) | |
#download vimrc bundles | |
vimrcBundlesFile = os.path.join(home, ".vimrc.bundles") | |
downloadURL(vimrcBundlesFile, vimBundlesUrl) | |
def downloadZipAndInstall(**kwargs): | |
name = kwargs.get("name") | |
url = kwargs.get("url") | |
path = kwargs.get("path") | |
option = kwargs.get("option", "") | |
file = name + ".zip" | |
print("downloadZipAndInstall {} {}".format(name, url)) | |
downloadURL(file, url) | |
if os.path.exists(path) is False: | |
print("makedirs {} ".format(path)) | |
os.makedirs(path) | |
CheckCall(["unzip", file, option, "-d", path]) | |
def main(): | |
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 1) | |
print(os.environ["USERPROFILE"]) | |
tasks = { | |
"sogou_pinyin": { | |
"func": installSogouPinyin, | |
"page": "https://pinyin.sogou.com/", | |
}, | |
"env_editor": { | |
"func": downloadExeAndInstall, | |
"url": "http://eveditor.com/downloads/EveditorFree-1.5.0.exe", | |
}, | |
"xshell": { | |
"func": downloadExeAndInstall, | |
"url": "https://softpedia-secure-download.com/dl/8a747b175758708c69b2e3d075217bf2/5b377005/100187987/software/network/Xshell-6.0.0091.exe", | |
}, | |
"qq": { | |
"func": downloadExeAndInstall, | |
"url": "https://dldir1.qq.com/qqfile/qq/QQ9.0.4/23780/QQ9.0.4.exe", | |
}, | |
"wechat": { | |
"func": downloadExeAndInstall, | |
"url": "http://dlglobal.qq.com/weixin/Windows/WeChat_C1018.exe", | |
}, | |
"vim-plugin": { | |
"func": installVimPlugin, | |
"vimPlugUrl": "https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim", | |
"vimrcUrl": "https://gist.githubusercontent.com/Alex-duzhichao/d9b19971e295c36b67531b7827f9453b/raw/3d787367326a3e04e3eddbcd1b997c3dd4f12492/vimrc", | |
"vimBundlesUrl": "https://gist.githubusercontent.com/Alex-duzhichao/2339c5c72557d7ffc1490c88059d6cff/raw/079407f53afcdea2da9234f16eaff5d1368ed354/vimrc.bundles", | |
}, | |
"ctags": { | |
"func": downloadZipAndInstall, | |
"url": "https://github.com/universal-ctags/ctags-win32/releases/download/2018-07-03%2F1e2c63fb/ctags-2018-07-03_1e2c63fb-x64.zip", | |
"path": os.path.join(os.environ["VIMPATH"], "bin"), | |
"option": "ctags.exe", | |
}, | |
"cscope": { | |
"func": downloadZipAndInstall, | |
"url": "https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/cscope-win32/cscope-15.8a-win64rev1-static.zip", | |
"path": os.path.join(os.environ["VIMPATH"], "bin"), | |
"option": "cscope.exe", | |
}, | |
} | |
if len(sys.argv) <= 1: | |
print("python installSoftware.py task_name") | |
print(tasks) | |
return | |
for task in sys.argv[1:]: | |
if task not in tasks: | |
raise TaskNotExistsError(task) | |
else: | |
val = tasks[task] | |
if readBoolChar("Do you want to install " + task) == False: | |
continue | |
val["name"] = task | |
func = val["func"] | |
func(**val) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment