Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: modules/adblockplus/files/web/static/deploy_script.py

Issue 29777652: #6145 - Introduce deploy script for websites (Closed)
Left Patch Set: Forgot to remove unused import Created May 22, 2018, 1:34 a.m.
Right Patch Set: Use of a different name convention for the script Created July 4, 2018, 2:12 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 #
3 # This file is part of the Adblock Plus infrastructure
4 # Copyright (C) 2018-present eyeo GmbH
5 #
6 # Adblock Plus is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License version 3 as
8 # published by the Free Software Foundation.
9 #
10 # Adblock Plus is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
2 17
3 import argparse 18 import argparse
4 from filecmp import dircmp 19 from filecmp import dircmp
5 import hashlib 20 import hashlib
6 import os 21 import os
7 import sys 22 import sys
8 import shutil 23 import shutil
9 import tarfile 24 import tarfile
10 import tempfile 25 import tempfile
11 import urllib 26 import urllib
12 import urllib2
13
14 _tmp_dir = tempfile.mkdtemp()
15 27
16 28
17 def download(url): 29 __doc__ = """This script MUST be renamed in the form of $WEBSITE, e.g.
30 help.eyeo.com, --name must be provided in order to fetch the
31 files, expected files to be fetched are $NAME.tar.gz and $NAME.md5 in
32 order to compare the hashes. --source must be an URL, e.g.
33 https://helpcenter.eyeofiles.com"""
34
35
36 def download(url, temporary_directory):
18 file_name = url.split('/')[-1] 37 file_name = url.split('/')[-1]
19 abs_file_name = os.path.join(_tmp_dir, file_name) 38 absolute_file_path = os.path.join(temporary_directory, file_name)
20 print 'Downloading: ' + file_name 39 print 'Downloading: ' + file_name
21 try: 40 urllib.urlretrieve(url, absolute_file_path)
22 filename, _ = urllib.urlretrieve(url, abs_file_name) 41 return absolute_file_path
Vasily Kuznetsov 2018/05/22 16:38:37 If you're throwing away `filename`, you can just i
f.lopez 2018/06/06 00:05:03 Acknowledged.
23 return abs_file_name
24 except urllib2.HTTPError as e:
25 if e.code == 404:
26 sys.exit('File not found on remote source')
27 except Exception as e:
28 sys.exit(e)
29 42
30 43
31 def calculate_md5(file): 44 def calculate_md5(file):
32 with open(file) as f: 45 with open(file) as file_handle:
33 data = f.read() 46 data = file_handle.read()
34 md5_result = hashlib.md5(data).hexdigest() 47 md5_result = hashlib.md5(data).hexdigest()
35 return md5_result.strip() 48 return md5_result.strip()
36 49
37 50
38 def read_md5(file): 51 def read_md5(file):
39 with open(file) as f: 52 with open(file) as file_handle:
40 md5_result = f.readline() 53 md5_result = file_handle.readline()
41 return md5_result.strip() 54 return md5_result.strip()
42 55
43 56
44 def untar(tar_file): 57 def untar(tar_file, temporary_directory):
45 if tarfile.is_tarfile(tar_file): 58 if tarfile.is_tarfile(tar_file):
46 with tarfile.open(tar_file, 'r:gz') as tar: 59 with tarfile.open(tar_file, 'r:gz') as tar:
47 tar.extractall(_tmp_dir) 60 tar.extractall(temporary_directory)
48 61
49 62
50 def remove_tree(to_remove): 63 def remove_tree(to_remove):
51 if os.path.exists(to_remove): 64 if os.path.exists(to_remove):
52 if os.path.isdir(to_remove): 65 if os.path.isdir(to_remove):
53 shutil.rmtree(to_remove) 66 shutil.rmtree(to_remove)
54 else: 67 else:
55 os.remove(to_remove) 68 os.remove(to_remove)
56 69
57 70
58 def deploy_files(dcmp): 71 def deploy_files(directory_comparison):
59 for name in dcmp.diff_files: 72 for name in directory_comparison.diff_files:
60 copytree(dcmp.right, dcmp.left) 73 copytree(directory_comparison.right, directory_comparison.left)
61 for name in dcmp.left_only: 74 for name in directory_comparison.left_only:
62 remove_tree(dcmp.left + "/" + name) 75 remove_tree(os.path.join(directory_comparison.left, name))
Vasily Kuznetsov 2018/05/23 12:25:43 It's more portable (and generally a better practic
f.lopez 2018/06/06 00:05:03 Acknowledged.
63 for name in dcmp.right_only: 76 for name in directory_comparison.right_only:
64 copytree(dcmp.right, dcmp.left) 77 copytree(directory_comparison.right, directory_comparison.left)
65 for sub_dcmp in dcmp.subdirs.values(): 78 for subdirectory_comparison in directory_comparison.subdirs.values():
66 deploy_files(sub_dcmp) 79 deploy_files(subdirectory_comparison)
67 80
68 81
69 def copytree(src, dst): 82 # shutil.copytree copies a tree but the destination directory MUST NOT exist
70 if not os.path.exists(dst): 83 # this might break the site for the duration of the files being deployed
71 os.makedirs(dst) 84 # for more info read: https://docs.python.org/2/library/shutil.html
72 shutil.copystat(src, dst) 85 def copytree(source, destination):
73 lst = os.listdir(src) 86 if not os.path.exists(destination):
74 for item in lst: 87 os.makedirs(destination)
75 s = os.path.join(src, item) 88 shutil.copystat(source, destination)
76 d = os.path.join(dst, item) 89 source_items = os.listdir(source)
77 if os.path.isdir(s): 90 for item in source_items:
78 copytree(s, d) 91 source_path = os.path.join(source, item)
92 destination_path = os.path.join(destination, item)
93 if os.path.isdir(source_path):
94 copytree(source_path, destination_path)
79 else: 95 else:
80 shutil.copy2(s, d) 96 shutil.copy2(source_path, destination_path)
81 97
82 98
83 if __name__ == '__main__': 99 if __name__ == '__main__':
100 website = os.path.basename(__file__)
84 parser = argparse.ArgumentParser( 101 parser = argparse.ArgumentParser(
85 description="""Fetch a compressed archive in the form of $HASH.tar.gz 102 description="""Fetch a compressed archive in the form of $NAME.tar.gz
86 and deploy it to /var/www/$WEBSITE folder""", 103 and deploy it to /var/www/{0} folder""".format(website),
87 epilog="""--hash must be provided in order to fetch the files, 104 epilog=__doc__,
88 expected files to be fetched are $HASH.tar.gz and $HASH.md5 in
89 order to compare the hashes.
90 --source must be an URL, e.g.
91 https://helpcenter.eyeofiles.com""",
92 ) 105 )
93 parser.add_argument('--hash', action='store', type=str, 106 parser.add_argument('--name', action='store', type=str, required=True,
94 nargs='?', required=True, 107 help='Name of the tarball to deploy')
95 help='Hash of the commit to deploy') 108 parser.add_argument('--source', action='store', type=str, required=True,
96 parser.add_argument('--source', action='store', type=str,
97 required=True, nargs='?',
Vasily Kuznetsov 2018/05/22 16:38:37 Won't nargs='?' make the argument (of --source) op
f.lopez 2018/06/06 00:05:03 Acknowledged.
98 help='The source where files will be downloaded') 109 help='The source where files will be downloaded')
99 parser.add_argument('--website', action='store', type=str, nargs='?', 110 arguments = parser.parse_args()
100 help='The name of the website [e.g. help.eyeo.com]') 111 name = arguments.name
101 args = parser.parse_args() 112 source = arguments.source
102 hash = args.hash 113 url_file = '{0}/{1}.tar.gz'.format(source, name)
103 source = args.source 114 url_md5 = '{0}/{1}.md5'.format(source, name)
104 url_file = '{0}/{1}.tar.gz'.format(source, hash) 115 temporary_directory = tempfile.mkdtemp()
105 url_md5 = '{0}/{1}.md5'.format(source, hash)
106 down_file = download(url_file)
107 down_md5 = download(url_md5)
108 try: 116 try:
109 if calculate_md5(down_file) == read_md5(down_md5): 117 downloaded_file = download(url_file, temporary_directory)
110 untar(down_file) 118 downloaded_md5 = download(url_md5, temporary_directory)
111 hash_directory = os.path.join(_tmp_dir, hash) 119 if calculate_md5(downloaded_file) == read_md5(downloaded_md5):
112 destination = '/var/www/' + args.website 120 untar(downloaded_file, temporary_directory)
Vasily Kuznetsov 2018/05/23 12:25:43 Maybe also `os.path.join`? Also, do you think it'
f.lopez 2018/06/06 00:05:03 This is not expected to change, since it is the de
113 dcmp = dircmp(destination, hash_directory) 121 tarball_directory = os.path.join(temporary_directory, name)
114 print "Deploying files" 122 destination = os.path.join('/var/www/', website)
Vasily Kuznetsov 2018/05/23 12:25:44 Remember the quotes rule ;P
f.lopez 2018/06/06 00:05:03 Oh my god...
115 deploy_files(dcmp) 123 directory_comparison = dircmp(destination, tarball_directory)
124 print 'Deploying files'
125 deploy_files(directory_comparison)
116 else: 126 else:
117 sys.exit("Hashes don't match") 127 error_message = """{0}.tar.gz md5 computation doesn't match {0}.md5
118 except Exception as e: 128 contents""".format(name)
119 sys.exit(e) 129 sys.exit(error_message)
130 except Exception as error:
131 sys.exit(error)
120 finally: 132 finally:
121 shutil.rmtree(_tmp_dir) 133 shutil.rmtree(temporary_directory)
Vasily Kuznetsov 2018/05/23 12:25:44 The temporary directory won't be deleted if downlo
f.lopez 2018/06/06 00:05:03 ok I like it, thanks
LEFTRIGHT
« no previous file | no next file » | Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Toggle Comments ('s')

Powered by Google App Engine
This is Rietveld