| Left: | ||
| Right: |
| LEFT | RIGHT |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 | 2 |
| 3 # This file is part of Adblock Plus <https://adblockplus.org/>, | 3 # This file is part of Adblock Plus <https://adblockplus.org/>, |
| 4 # Copyright (C) 2006-2016 Eyeo GmbH | 4 # Copyright (C) 2006-2016 Eyeo GmbH |
| 5 # | 5 # |
| 6 # 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 |
| 7 # 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 |
| 8 # published by the Free Software Foundation. | 8 # published by the Free Software Foundation. |
| 9 # | 9 # |
| 10 # 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, |
| 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 # GNU General Public License for more details. | 13 # GNU General Public License for more details. |
| 14 # | 14 # |
| 15 # 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 |
| 16 # 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/>. |
| 17 | 17 |
| 18 import os | 18 import os |
| 19 import shutil | 19 import shutil |
| 20 import subprocess | 20 import subprocess |
| 21 | 21 |
| 22 from sitescripts.utils import get_config | 22 from sitescripts.utils import get_config |
| 23 | 23 |
| 24 def read_projects(): | 24 def read_projects(config): |
| 25 projects = {} | 25 projects = {} |
| 26 for key, value in get_config().items("docs"): | 26 for key, value in config.items("docs"): |
| 27 key_parts = key.split("_", 1) | 27 key_parts = key.split("_", 1) |
| 28 if len(key_parts) < 2: | 28 if len(key_parts) < 2: |
| 29 continue | 29 continue |
| 30 project_name, field_name = key_parts | 30 project_name, field_name = key_parts |
| 31 if field_name not in {"repository", "target_directory", "command"}: | 31 if field_name not in {"repository", "target_directory", "command"}: |
| 32 continue | 32 continue |
| 33 projects.setdefault(project_name, {})[field_name] = value | 33 projects.setdefault(project_name, {})[field_name] = value |
| 34 return projects | 34 return projects |
| 35 | 35 |
| 36 def sync_sources(sources_dir, repository_url): | 36 def sync_sources(sources_dir, repository_url): |
| 37 remote_id = subprocess.check_output(["hg", "id", "--id", repository_url]) | 37 if os.path.exists(sources_dir): |
| 38 id_path = sources_dir.rstrip(os.path.sep) + ".id" | 38 subprocess.check_call(["hg", "pull", "--quiet", |
| 39 try: | 39 "--rev", "master", |
| 40 with open(id_path, "rb") as id_file: | 40 "--repository", sources_dir]) |
| 41 local_id = id_file.read() | 41 subprocess.check_call(["hg", "update", "--quiet", |
| 42 if local_id == remote_id: | 42 "--rev", "master"]) |
| 43 return | 43 else: |
| 44 except IOError: | 44 subprocess.check_call(["hg", "clone", "--quiet", |
| 45 pass | 45 "--updaterev", "master", |
| 46 | 46 repository_url, sources_dir]) |
| 47 try: | |
| 48 shutil.rmtree(sources_dir) | |
| 49 except OSError: | |
|
Sebastian Noack
2016/02/06 09:49:50
shutil.rmtree() has an ingnore_errors argument.
Felix Dahlke
2016/02/06 10:46:40
Awesome, I was very unhappy with all this boiler p
| |
| 50 pass | |
| 51 | |
| 52 subprocess.check_call(["hg", "archive", | |
| 53 "--repository", repository_url, | |
| 54 "--rev", "master", | |
| 55 sources_dir]) | |
| 56 | |
| 57 # In theory, it is possible that some changesets are pushed after we fetch | |
| 58 # the ID above, but before we run `hg archive`, which will lead to an | |
| 59 # unnecessary `hg archive` operation the next time this runs. | |
| 60 with open(id_path, "wb") as id_file: | |
| 61 id_file.write(remote_id) | |
| 62 | |
| 63 # Because of how ensure_dependencies.py works, we have to create fake .hg | |
|
Felix Dahlke
2016/02/05 20:47:59
I discovered that ensure_dependencies.py, being re
Sebastian Noack
2016/02/05 22:46:18
Moreover, build.py requires buildtools, and if you
Felix Dahlke
2016/02/06 06:42:55
Since I invoke the repository's build.py here, tha
Sebastian Noack
2016/02/06 09:49:50
Yeah, I missed something. You are right. That shou
Felix Dahlke
2016/02/06 10:46:40
Done.
| |
| 64 # directories in each source directory. | |
| 65 os.makedirs(os.path.join(sources_dir, ".hg")) | |
| 66 | 47 |
| 67 def replace_dir(source_dir, target_dir): | 48 def replace_dir(source_dir, target_dir): |
| 68 if not os.path.exists(target_dir): | 49 if not os.path.exists(target_dir): |
| 69 parent_dir = os.path.dirname(target_dir) | 50 parent_dir = os.path.dirname(target_dir) |
| 70 try: | 51 try: |
| 71 os.makedirs(parent_dir) | 52 os.makedirs(parent_dir) |
| 72 except OSError: | 53 except OSError: |
| 73 pass | 54 pass |
| 74 os.rename(source_dir, target_dir) | 55 os.rename(source_dir, target_dir) |
| 75 else: | 56 else: |
| 76 old_target_dir = target_dir.rstrip(os.path.sep) + ".old" | 57 old_target_dir = target_dir.rstrip(os.path.sep) + ".old" |
|
Sebastian Noack
2016/02/06 09:49:50
Generating backups seems to be unnecessary as the
Felix Dahlke
2016/02/06 10:46:39
This isn't really a backup, it's just so that repl
Sebastian Noack
2016/02/06 13:39:39
Acknowledged.
| |
| 77 try: | 58 shutil.rmtree(old_target_dir, ignore_errors=True) |
| 78 shutil.rmtree(old_target_dir) | |
| 79 except OSError: | |
| 80 pass | |
| 81 os.rename(target_dir, old_target_dir) | 59 os.rename(target_dir, old_target_dir) |
| 82 os.rename(source_dir, target_dir) | 60 os.rename(source_dir, target_dir) |
| 83 shutil.rmtree(old_target_dir) | 61 shutil.rmtree(old_target_dir) |
| 84 | 62 |
| 85 def run_generation_command(command, sources_dir, output_dir): | 63 def run_generation_command(command, sources_dir, output_dir): |
| 86 try: | 64 shutil.rmtree(output_dir, ignore_errors=True) |
| 87 shutil.rmtree(output_dir) | |
| 88 except OSError: | |
| 89 pass | |
| 90 command = command.format(output_dir=output_dir) | 65 command = command.format(output_dir=output_dir) |
| 91 subprocess.check_call(command, shell=True, cwd=sources_dir) | 66 subprocess.check_call(command, shell=True, cwd=sources_dir) |
| 92 | 67 |
| 93 def generate_docs(projects): | 68 def generate_docs(projects, config): |
| 94 temp_directory = get_config().get("docs", "temp_directory") | 69 temp_directory = config.get("docs", "temp_directory") |
| 95 try: | 70 try: |
| 96 os.makedirs(temp_directory) | 71 os.makedirs(temp_directory) |
| 97 except OSError: | 72 except OSError: |
| 98 pass | 73 pass |
| 99 | 74 |
| 100 for name, data in projects.iteritems(): | 75 for name, data in projects.iteritems(): |
| 101 sources_dir = os.path.join(temp_directory, name) | 76 sources_dir = os.path.join(temp_directory, name) |
| 102 sync_sources(sources_dir, data["repository"]) | 77 sync_sources(sources_dir, data["repository"]) |
| 103 output_dir = sources_dir.rstrip(os.path.sep) + ".docs" | 78 output_dir = sources_dir.rstrip(os.path.sep) + ".docs" |
| 104 run_generation_command(data["command"], sources_dir, output_dir) | 79 run_generation_command(data["command"], sources_dir, output_dir) |
| 105 replace_dir(output_dir, data["target_directory"]) | 80 replace_dir(output_dir, data["target_directory"]) |
| 106 | 81 |
| 107 if __name__ == "__main__": | 82 if __name__ == "__main__": |
|
Sebastian Noack
2016/02/06 09:49:51
How about calling get_config() here and passing th
Felix Dahlke
2016/02/06 10:46:39
Done.
| |
| 108 projects = read_projects() | 83 config = get_config() |
| 109 generate_docs(projects) | 84 projects = read_projects(config) |
| 85 generate_docs(projects, config) | |
| LEFT | RIGHT |