Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # coding: utf-8 | |
Sebastian Noack
2016/02/05 18:02:32
Not that a coding declaration is necessary here. M
Felix Dahlke
2016/02/05 20:47:58
Wow true, either that part changed or we misunders
| |
3 | 2 |
4 # This file is part of Adblock Plus <https://adblockplus.org/>, | 3 # This file is part of Adblock Plus <https://adblockplus.org/>, |
5 # Copyright (C) 2006-2016 Eyeo GmbH | 4 # Copyright (C) 2006-2016 Eyeo GmbH |
6 # | 5 # |
7 # Adblock Plus is free software: you can redistribute it and/or modify | 6 # Adblock Plus is free software: you can redistribute it and/or modify |
8 # it under the terms of the GNU General Public License version 3 as | 7 # it under the terms of the GNU General Public License version 3 as |
9 # published by the Free Software Foundation. | 8 # published by the Free Software Foundation. |
10 # | 9 # |
11 # Adblock Plus is distributed in the hope that it will be useful, | 10 # Adblock Plus is distributed in the hope that it will be useful, |
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 # GNU General Public License for more details. | 13 # GNU General Public License for more details. |
15 # | 14 # |
16 # You should have received a copy of the GNU General Public License | 15 # You should have received a copy of the GNU General Public License |
17 # along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. | 16 # along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
18 | 17 |
19 import os | 18 import os |
20 import shutil | 19 import shutil |
21 import subprocess | 20 import subprocess |
22 | 21 |
23 from sitescripts.utils import get_config | 22 from sitescripts.utils import get_config |
24 | 23 |
25 config = dict(get_config().items("docs")) | 24 def read_projects(config): |
Sebastian Noack
2016/02/05 18:02:31
I'd prefer if you use the ConfigParser API consist
Felix Dahlke
2016/02/05 20:47:57
Done.
| |
26 | |
27 def read_projects(): | |
28 projects = {} | 25 projects = {} |
29 for key, value in config.iteritems(): | 26 for key, value in config.items("docs"): |
30 key_parts = key.split("_", 1) | 27 key_parts = key.split("_", 1) |
31 if len(key_parts) < 2: | 28 if len(key_parts) < 2: |
32 continue | 29 continue |
33 project_name, field_name = key_parts | 30 project_name, field_name = key_parts |
34 if field_name not in ["repository", "target_directory", "command"]: | 31 if field_name not in {"repository", "target_directory", "command"}: |
Sebastian Noack
2016/02/05 18:02:32
Nit: A set seems more appropriate here. In case yo
Felix Dahlke
2016/02/05 20:47:58
No I didn't, nice. Done.
| |
35 continue | 32 continue |
36 projects.setdefault(project_name, {}) | 33 projects.setdefault(project_name, {})[field_name] = value |
Sebastian Noack
2016/02/05 18:02:31
There is a reason that setdefault() returns the re
Felix Dahlke
2016/02/05 20:47:58
Done.
| |
37 projects[project_name][field_name] = value | |
38 return projects | 34 return projects |
39 | 35 |
40 def sync_sources(sources_dir, repository_url): | 36 def sync_sources(sources_dir, repository_url): |
41 remote_id = subprocess.check_output(["hg", "id", "-i", repository_url]) | |
Sebastian Noack
2016/02/05 18:02:32
Nit: Please use long option names in scripts, that
Felix Dahlke
2016/02/05 20:47:58
Done.
| |
42 id_path = sources_dir.rstrip("/") + ".id" | |
Sebastian Noack
2016/02/05 18:02:31
Please don't hard-code file separators, use.ospath
Felix Dahlke
2016/02/05 20:47:58
Done.
| |
43 if os.path.exists(id_path): | |
Sebastian Noack
2016/02/05 18:02:31
It's better to handle the corresponding IOError, r
Felix Dahlke
2016/02/05 20:47:57
Fair enough, I've gotten rid of the os.path.exists
| |
44 with open(id_path, "r") as id_file: | |
Sebastian Noack
2016/02/05 18:02:32
Please always add "b" to the file mode, for consis
Felix Dahlke
2016/02/05 20:47:58
Done.
| |
45 local_id = id_file.read() | |
46 if local_id == remote_id: | |
47 return | |
48 if os.path.exists(sources_dir): | 37 if os.path.exists(sources_dir): |
49 shutil.rmtree(sources_dir) | 38 subprocess.check_call(["hg", "pull", "--quiet", |
50 subprocess.check_call(["hg", "archive", "-R", repository_url, "-r", "master", | 39 "--rev", "master", |
51 sources_dir]) | 40 "--repository", sources_dir]) |
52 | 41 subprocess.check_call(["hg", "update", "--quiet", |
53 # In theory, it is possible that some changesets are pushed after we fetch | 42 "--rev", "master"]) |
54 # the ID above, but before we run `hg archive`, which will lead to an | 43 else: |
55 # unnecessary `hg archive` operation the next time this runs. | 44 subprocess.check_call(["hg", "clone", "--quiet", |
56 with open(id_path, "w") as id_file: | 45 "--updaterev", "master", |
57 id_file.write(remote_id) | 46 repository_url, sources_dir]) |
58 | 47 |
59 def replace_dir(source_dir, target_dir): | 48 def replace_dir(source_dir, target_dir): |
60 if not os.path.exists(target_dir): | 49 if not os.path.exists(target_dir): |
61 parent_dir = os.path.dirname(target_dir) | 50 parent_dir = os.path.dirname(target_dir) |
62 if not os.path.exists(parent_dir): | 51 try: |
63 os.makedirs(parent_dir) | 52 os.makedirs(parent_dir) |
53 except OSError: | |
54 pass | |
64 os.rename(source_dir, target_dir) | 55 os.rename(source_dir, target_dir) |
65 else: | 56 else: |
66 old_target_dir = target_dir.rstrip("/") + ".old" | 57 old_target_dir = target_dir.rstrip(os.path.sep) + ".old" |
67 if os.path.exists(old_target_dir): | 58 shutil.rmtree(old_target_dir, ignore_errors=True) |
68 shutil.rmtree(old_target_dir) | |
69 os.rename(target_dir, old_target_dir) | 59 os.rename(target_dir, old_target_dir) |
70 os.rename(source_dir, target_dir) | 60 os.rename(source_dir, target_dir) |
71 shutil.rmtree(old_target_dir) | 61 shutil.rmtree(old_target_dir) |
72 | 62 |
73 def run_generation_command(command, sources_dir, output_dir): | 63 def run_generation_command(command, sources_dir, output_dir): |
74 if os.path.exists(output_dir): | 64 shutil.rmtree(output_dir, ignore_errors=True) |
75 shutil.rmtree(output_dir) | |
76 command = command.format(output_dir=output_dir) | 65 command = command.format(output_dir=output_dir) |
77 subprocess.check_call(command, shell=True, cwd=sources_dir) | 66 subprocess.check_call(command, shell=True, cwd=sources_dir) |
78 | 67 |
79 def generate_docs(projects): | 68 def generate_docs(projects, config): |
80 temp_directory = config["temp_directory"] | 69 temp_directory = config.get("docs", "temp_directory") |
81 if not os.path.exists(temp_directory): | 70 try: |
82 os.makedirs(temp_directory) | 71 os.makedirs(temp_directory) |
72 except OSError: | |
73 pass | |
83 | 74 |
84 for name, data in projects.iteritems(): | 75 for name, data in projects.iteritems(): |
85 sources_dir = os.path.join(temp_directory, name) | 76 sources_dir = os.path.join(temp_directory, name) |
86 sync_sources(sources_dir, data["repository"]) | 77 sync_sources(sources_dir, data["repository"]) |
87 output_dir = sources_dir.rstrip("/") + ".docs" | 78 output_dir = sources_dir.rstrip(os.path.sep) + ".docs" |
88 run_generation_command(data["command"], sources_dir, output_dir) | 79 run_generation_command(data["command"], sources_dir, output_dir) |
89 replace_dir(output_dir, data["target_directory"]) | 80 replace_dir(output_dir, data["target_directory"]) |
90 | 81 |
91 if __name__ == "__main__": | 82 if __name__ == "__main__": |
92 projects = read_projects() | 83 config = get_config() |
93 generate_docs(projects) | 84 projects = read_projects(config) |
85 generate_docs(projects, config) | |
LEFT | RIGHT |