| Left: | ||
| Right: |
| OLD | NEW |
|---|---|
| (Empty) | |
| 1 #!/usr/bin/env python | |
| 2 | |
| 3 import argparse | |
| 4 from contextlib import closing | |
| 5 from filecmp import dircmp | |
| 6 import hashlib | |
| 7 import os | |
| 8 import sys | |
| 9 import shutil | |
| 10 import tarfile | |
| 11 import urllib2 | |
| 12 | |
| 13 | |
| 14 def download(url): | |
| 15 file_name = url.split('/')[-1] | |
| 16 abs_file_name = os.path.join(os.path.dirname(os.path.realpath(__file__)), | |
|
Vasily Kuznetsov
2018/05/15 18:09:37
It seems that you are using the directory of this
f.lopez
2018/05/21 22:23:41
Acknowledged.
| |
| 17 file_name) | |
| 18 print 'Downloading: ' + file_name | |
| 19 try: | |
| 20 with closing(urllib2.urlopen(url)) as page: | |
|
Vasily Kuznetsov
2018/05/15 18:09:37
This code is more or less doing `urllib.urlretriev
f.lopez
2018/05/21 22:23:41
Acknowledged.
| |
| 21 block_sz = 8912 | |
| 22 with open(abs_file_name, 'wb') as f: | |
| 23 while True: | |
| 24 buffer = page.read(block_sz) | |
| 25 if not buffer: | |
| 26 break | |
| 27 f.write(buffer) | |
| 28 return abs_file_name | |
| 29 except urllib2.HTTPError as e: | |
| 30 if e.code == 404: | |
| 31 sys.exit("File not found on remote source") | |
|
Vasily Kuznetsov
2018/05/15 18:09:37
We have a rule for selecting the type of quotes in
f.lopez
2018/05/21 22:23:41
Acknowledged.
| |
| 32 except Exception as e: | |
| 33 sys.exit(e) | |
| 34 | |
| 35 | |
| 36 def calculate_md5(file): | |
| 37 with open(file) as f: | |
| 38 data = f.read() | |
| 39 md5_result = hashlib.md5(data).hexdigest() | |
| 40 return md5_result.strip() | |
| 41 | |
| 42 | |
| 43 def read_md5(file): | |
| 44 with open(file) as f: | |
| 45 md5_result = f.readline() | |
| 46 return md5_result.strip() | |
| 47 | |
| 48 | |
| 49 def untar(tar_file): | |
| 50 if tarfile.is_tarfile(tar_file): | |
| 51 with tarfile.open(tar_file, 'r:gz') as tar: | |
| 52 tar.extractall(os.path.dirname(os.path.realpath(tar_file))) | |
| 53 print 'Extracted in current directory' | |
| 54 return os.path.dirname(os.path.abspath(__file__)) | |
| 55 | |
| 56 | |
| 57 def remove_tree(to_remove): | |
| 58 if os.path.exists(to_remove): | |
| 59 if os.path.isdir(to_remove): | |
| 60 shutil.rmtree(to_remove) | |
| 61 else: | |
| 62 os.remove(to_remove) | |
| 63 | |
| 64 | |
| 65 def clean(hash): | |
| 66 print "cleaning directory" | |
| 67 cwd = os.path.dirname(os.path.abspath(__file__)) | |
| 68 [remove_tree(os.path.join(cwd, x)) for x in os.listdir(cwd) | |
| 69 if x.startswith(hash)] | |
| 70 | |
| 71 | |
| 72 def deploy_files(dcmp): | |
| 73 for name in dcmp.diff_files: | |
| 74 copytree(dcmp.right, dcmp.left) | |
| 75 for name in dcmp.left_only: | |
| 76 remove_tree(dcmp.left + "/" + name) | |
| 77 for name in dcmp.right_only: | |
| 78 copytree(dcmp.right, dcmp.left) | |
| 79 for sub_dcmp in dcmp.subdirs.values(): | |
| 80 deploy_files(sub_dcmp) | |
| 81 | |
| 82 | |
| 83 def copytree(src, dst): | |
| 84 if not os.path.exists(dst): | |
| 85 os.makedirs(dst) | |
| 86 shutil.copystat(src, dst) | |
| 87 lst = os.listdir(src) | |
| 88 for item in lst: | |
| 89 s = os.path.join(src, item) | |
| 90 d = os.path.join(dst, item) | |
| 91 if os.path.isdir(s): | |
| 92 copytree(s, d) | |
| 93 else: | |
| 94 shutil.copy2(s, d) | |
| 95 | |
| 96 | |
| 97 if __name__ == '__main__': | |
| 98 parser = argparse.ArgumentParser( | |
| 99 description='''Fetch a compressed archive in the form of $HASH.tar.gz an d | |
|
Vasily Kuznetsov
2018/05/15 18:09:37
"Fetch" and "deploys" is inconsistent. It should b
Vasily Kuznetsov
2018/05/15 18:09:37
It's nicer to be consistent with the type of quote
f.lopez
2018/05/21 22:23:41
Acknowledged.
f.lopez
2018/05/21 22:23:41
Acknowledged.
| |
| 100 deploys it to /var/www/$WEBSITE folder''', | |
| 101 epilog="""--hash must be provided in order to fetch the files, | |
| 102 expected files to be fetched are $HASH.tar.gz and $HASH.md5 in order to | |
|
Vasily Kuznetsov
2018/05/15 18:09:37
This indentation is a bit hard to follow. Perhaps
f.lopez
2018/05/21 22:23:42
Acknowledged.
| |
| 103 compare the hashes. | |
| 104 --url and --domain are mutually exclusive, if url is provided | |
| 105 the files will be downloaded from $url/$HASH, otherwise the default | |
| 106 value will be fetched from $domain.eyeofiles.com/$HASH""", | |
| 107 ) | |
| 108 parser.add_argument('--hash', action='store', type=str, nargs='?', | |
|
Vasily Kuznetsov
2018/05/15 18:09:37
'store' is the default action, so you don't really
f.lopez
2018/05/21 22:23:41
I know this is the default action, but I think it
Vasily Kuznetsov
2018/05/22 16:38:36
Acknowledged.
| |
| 109 help='Hash of the commit to deploy') | |
| 110 parser.add_argument('--url', action='store', type=str, | |
| 111 help='URL where files will be downloaded') | |
| 112 parser.add_argument('--domain', action='store', type=str, nargs='?', | |
| 113 help='''The domain to prepend | |
| 114 [eg. https://$domain.eyeofiles.com]''') | |
| 115 parser.add_argument('--website', action='store', type=str, nargs='?', | |
| 116 help='The name of the website [e.g. help.eyeo.com]') | |
| 117 args = parser.parse_args() | |
| 118 hash = args.hash | |
| 119 domain = args.domain | |
| 120 if args.url: | |
| 121 url_file = '{0}/{1}.tar.gz'.format(args.url, hash) | |
| 122 url_md5 = '{0}/{1}.md5'.format(args.url, hash) | |
| 123 else: | |
| 124 url_file = 'https://{0}.eyeofiles.com/{1}.tar.gz'.format(domain, hash) | |
|
Vasily Kuznetsov
2018/05/15 18:09:37
What if --domain is not provided?
f.lopez
2018/05/21 22:23:41
You are right, I think it's better if I only provi
Vasily Kuznetsov
2018/05/22 16:38:36
Acknowledged.
| |
| 125 url_md5 = 'https://{0}.eyeofiles.com/{1}.md5'.format(domain, hash) | |
| 126 down_file = download(url_file) | |
| 127 down_md5 = download(url_md5) | |
| 128 if calculate_md5(down_file) == read_md5(down_md5): | |
| 129 tar_directory = untar(down_file) | |
| 130 hash_directory = os.path.join(tar_directory, hash) | |
| 131 destination = '/var/www/' + args.website | |
| 132 dcmp = dircmp(destination, hash_directory) | |
| 133 deploy_files(dcmp) | |
| 134 clean(hash) | |
|
Vasily Kuznetsov
2018/05/15 18:09:37
`clean()` won't be called in cases of errors -- is
f.lopez
2018/05/21 22:23:42
Acknowledged.
| |
| 135 else: | |
| 136 sys.exit("Hashes don't match") | |
| OLD | NEW |