-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
/
base.py
136 lines (107 loc) · 4.19 KB
/
base.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# -*- coding: utf-8 -*-
"""Base classes for Builders."""
import logging
import os
import shutil
from functools import wraps
log = logging.getLogger(__name__)
def restoring_chdir(fn):
# XXX:dc: This would be better off in a neutral module
@wraps(fn)
def decorator(*args, **kw):
try:
path = os.getcwd()
return fn(*args, **kw)
finally:
os.chdir(path)
return decorator
class BaseBuilder:
"""
The Base for all Builders. Defines the API for subclasses.
Expects subclasses to define ``old_artifact_path``, which points at the
directory where artifacts should be copied from.
"""
_force = False
ignore_patterns = []
# old_artifact_path = ..
def __init__(self, build_env, python_env, force=False):
self.build_env = build_env
self.python_env = python_env
self.version = build_env.version
self.project = build_env.project
self.config = python_env.config if python_env else None
self._force = force
self.target = self.project.artifact_path(
version=self.version.slug,
type_=self.type,
)
def force(self, **__):
"""An optional step to force a build even when nothing has changed."""
log.info('Forcing a build')
self._force = True
def build(self):
"""Do the actual building of the documentation."""
raise NotImplementedError
def move(self, **__):
"""Move the generated documentation to its artifact directory."""
if os.path.exists(self.old_artifact_path):
if os.path.exists(self.target):
shutil.rmtree(self.target)
log.info('Copying %s on the local filesystem', self.type)
log.debug('Ignoring patterns %s', self.ignore_patterns)
shutil.copytree(
self.old_artifact_path,
self.target,
ignore=shutil.ignore_patterns(*self.ignore_patterns),
)
else:
log.warning('Not moving docs, because the build dir is unknown.')
def clean(self, **__):
"""Clean the path where documentation will be built."""
if os.path.exists(self.old_artifact_path):
shutil.rmtree(self.old_artifact_path)
log.info('Removing old artifact path: %s', self.old_artifact_path)
def docs_dir(self, docs_dir=None, **__):
"""Handle creating a custom docs_dir if it doesn't exist."""
checkout_path = self.project.checkout_path(self.version.slug)
if not docs_dir:
for doc_dir_name in ['docs', 'doc', 'Doc', 'book']:
possible_path = os.path.join(checkout_path, doc_dir_name)
if os.path.exists(possible_path):
docs_dir = possible_path
break
if not docs_dir:
docs_dir = checkout_path
return docs_dir
def create_index(self, extension='md', **__):
"""Create an index file if it needs it."""
docs_dir = self.docs_dir()
index_filename = os.path.join(
docs_dir,
'index.{ext}'.format(ext=extension),
)
if not os.path.exists(index_filename):
readme_filename = os.path.join(
docs_dir,
'README.{ext}'.format(ext=extension),
)
if os.path.exists(readme_filename):
return 'README'
index_file = open(index_filename, 'w+')
index_text = """
Welcome to Read the Docs
------------------------
This is an autogenerated index file.
Please create an ``index.{ext}`` or ``README.{ext}`` file with your own content
under the root (or ``/docs``) directory in your repository.
If you want to use another markup, choose a different builder in your settings.
Check out our `Getting Started Guide
<https://docs.readthedocs.io/en/latest/getting_started.html>`_ to become more
familiar with Read the Docs.
"""
index_file.write(index_text.format(dir=docs_dir, ext=extension))
index_file.close()
return 'index'
def run(self, *args, **kwargs):
"""Proxy run to build environment."""
return self.build_env.run(*args, **kwargs)