Skip to content

Commit eeb41f9

Browse files
authored
Merge branch 'master' into 2720-upgrade-pygments
2 parents a4a6a28 + bb36f34 commit eeb41f9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+1263
-283
lines changed

README.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ Purpose
99
`Read the Docs`_ hosts documentation for the open source community. It supports
1010
Sphinx_ docs written with reStructuredText_, and can pull from your Subversion_,
1111
Bazaar_, Git_, and Mercurial_ repositories.
12+
Then we build documentation and host it for you.
13+
Think of it as *Continuous Documentation*.
1214

1315
.. _Read the docs: http://readthedocs.org/
1416
.. _Sphinx: http://sphinx.pocoo.org/

bower.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"jquery": "2.0.3",
1818
"underscore": "~1.7.0",
1919
"readthedocs-client": "https://github.com/agjohnson/readthedocs-client-js.git",
20-
"sphinx-rtd-theme": "https://github.com/snide/sphinx-rtd-theme.git#0.1.9",
20+
"sphinx-rtd-theme": "https://github.com/snide/sphinx-rtd-theme.git#0.2.4",
2121
"knockout": "~3.3.0",
2222
"jquery.payment": "~1.3.0",
2323
"jquery-migrate": "~1.2.1",

docs/webhooks.rst

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,18 @@ your docs whenever you push updates:
4040
If you ever need to manually set the webhook on Bitbucket,
4141
you can point it at ``https://readthedocs.org/bitbucket``.
4242

43+
GitLab
44+
---------
45+
46+
If your project is hosted on GitLab, you can easily add a hook that will rebuild
47+
your docs whenever you push updates.
48+
49+
* Go to the "Settings" page for your project
50+
* Click "Integrations"
51+
* In the "URL" section, enter ``https://readthedocs.org/gitlab``
52+
* Leave the default "Push events" selected
53+
* Click "Add Webhook"
54+
4355
Others
4456
------
4557

@@ -53,7 +65,7 @@ The following parameters available to customize the behavior of custom webhooks:
5365
* ``'version_slug'``: The build version to trigger build for (defaults to ``'latest'``)
5466

5567
Example::
56-
68+
5769
$ curl -X POST --data "version_slug=$VERSION" https://readthedocs.org/build/$PROJECT_NAME
5870

5971
You could make this part of a hook using Git_, Subversion_, Mercurial_, or

media/css/core.css

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,3 +1029,105 @@ select.dropdown { display: none; }
10291029

10301030
.domain-machine { color: #999; }
10311031
.domain-canonical { font-weight: bold; }
1032+
1033+
/* Integrations */
1034+
div.module-list-wrapper.httpexchanges li span.status {
1035+
padding: .2em .4em;
1036+
margin-right: .3em;
1037+
border-radius: .3em;
1038+
color: #fff;
1039+
}
1040+
div.module-list-wrapper.httpexchanges li span.status.status-pass {
1041+
background: #5a5;
1042+
}
1043+
div.module-list-wrapper.httpexchanges li span.status.status-fail {
1044+
background: #a55;
1045+
}
1046+
1047+
div.httpexchange dl dt {
1048+
display: inline-block;
1049+
font-weight: bold;
1050+
font-family: 'inconsolata', 'bitstream vera sans mono', 'andale mono', 'lucida console', monospace;
1051+
font-size: .9em;
1052+
}
1053+
1054+
div.httpexchange dl dd {
1055+
display: inline;
1056+
font-family: 'inconsolata', 'bitstream vera sans mono', 'andale mono', 'lucida console', monospace;
1057+
font-size: .9em;
1058+
}
1059+
div.httpexchange dl dd:after {
1060+
display: block;
1061+
content: '';
1062+
}
1063+
1064+
div.httpexchange div.highlight pre {
1065+
padding: 1em;
1066+
background: #f4f4f4;
1067+
border: 1px solid #ccc;
1068+
font-size: .9em;
1069+
}
1070+
1071+
/* Pygments */
1072+
div.highlight pre .hll { background-color: #ffffcc }
1073+
div.highlight pre .c { color: #60a0b0; font-style: italic } /* Comment */
1074+
div.highlight pre .err { border: 1px solid #FF0000 } /* Error */
1075+
div.highlight pre .k { color: #007020; font-weight: bold } /* Keyword */
1076+
div.highlight pre .o { color: #666666 } /* Operator */
1077+
div.highlight pre .cm { color: #60a0b0; font-style: italic } /* Comment.Multiline */
1078+
div.highlight pre .cp { color: #007020 } /* Comment.Preproc */
1079+
div.highlight pre .c1 { color: #60a0b0; font-style: italic } /* Comment.Single */
1080+
div.highlight pre .cs { color: #60a0b0; background-color: #fff0f0 } /* Comment.Special */
1081+
div.highlight pre .gd { color: #A00000 } /* Generic.Deleted */
1082+
div.highlight pre .ge { font-style: italic } /* Generic.Emph */
1083+
div.highlight pre .gr { color: #FF0000 } /* Generic.Error */
1084+
div.highlight pre .gh { color: #000080; font-weight: bold } /* Generic.Heading */
1085+
div.highlight pre .gi { color: #00A000 } /* Generic.Inserted */
1086+
div.highlight pre .go { color: #888888 } /* Generic.Output */
1087+
div.highlight pre .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
1088+
div.highlight pre .gs { font-weight: bold } /* Generic.Strong */
1089+
div.highlight pre .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
1090+
div.highlight pre .gt { color: #0044DD } /* Generic.Traceback */
1091+
div.highlight pre .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
1092+
div.highlight pre .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
1093+
div.highlight pre .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
1094+
div.highlight pre .kp { color: #007020 } /* Keyword.Pseudo */
1095+
div.highlight pre .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
1096+
div.highlight pre .kt { color: #902000 } /* Keyword.Type */
1097+
div.highlight pre .m { color: #40a070 } /* Literal.Number */
1098+
div.highlight pre .s { color: #4070a0 } /* Literal.String */
1099+
div.highlight pre .na { color: #4070a0 } /* Name.Attribute */
1100+
div.highlight pre .nb { color: #007020 } /* Name.Builtin */
1101+
div.highlight pre .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
1102+
div.highlight pre .no { color: #60add5 } /* Name.Constant */
1103+
div.highlight pre .nd { color: #555555; font-weight: bold } /* Name.Decorator */
1104+
div.highlight pre .ni { color: #d55537; font-weight: bold } /* Name.Entity */
1105+
div.highlight pre .ne { color: #007020 } /* Name.Exception */
1106+
div.highlight pre .nf { color: #06287e } /* Name.Function */
1107+
div.highlight pre .nl { color: #002070; font-weight: bold } /* Name.Label */
1108+
div.highlight pre .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
1109+
div.highlight pre .nt { color: #062873; font-weight: bold } /* Name.Tag */
1110+
div.highlight pre .nv { color: #bb60d5 } /* Name.Variable */
1111+
div.highlight pre .ow { color: #007020; font-weight: bold } /* Operator.Word */
1112+
div.highlight pre .w { color: #bbbbbb } /* Text.Whitespace */
1113+
div.highlight pre .mb { color: #40a070 } /* Literal.Number.Bin */
1114+
div.highlight pre .mf { color: #40a070 } /* Literal.Number.Float */
1115+
div.highlight pre .mh { color: #40a070 } /* Literal.Number.Hex */
1116+
div.highlight pre .mi { color: #40a070 } /* Literal.Number.Integer */
1117+
div.highlight pre .mo { color: #40a070 } /* Literal.Number.Oct */
1118+
div.highlight pre .sb { color: #4070a0 } /* Literal.String.Backtick */
1119+
div.highlight pre .sc { color: #4070a0 } /* Literal.String.Char */
1120+
div.highlight pre .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
1121+
div.highlight pre .s2 { color: #4070a0 } /* Literal.String.Double */
1122+
div.highlight pre .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
1123+
div.highlight pre .sh { color: #4070a0 } /* Literal.String.Heredoc */
1124+
div.highlight pre .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
1125+
div.highlight pre .sx { color: #c65d09 } /* Literal.String.Other */
1126+
div.highlight pre .sr { color: #235388 } /* Literal.String.Regex */
1127+
div.highlight pre .s1 { color: #4070a0 } /* Literal.String.Single */
1128+
div.highlight pre .ss { color: #517918 } /* Literal.String.Symbol */
1129+
div.highlight pre .bp { color: #007020 } /* Name.Builtin.Pseudo */
1130+
div.highlight pre .vc { color: #bb60d5 } /* Name.Variable.Class */
1131+
div.highlight pre .vg { color: #bb60d5 } /* Name.Variable.Global */
1132+
div.highlight pre .vi { color: #bb60d5 } /* Name.Variable.Instance */
1133+
div.highlight pre .il { color: #40a070 } /* Literal.Number.Integer.Long */

media/javascript/rtd.js

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@
6767
}
6868
);
6969

70-
checkVersion(slug, version);
70+
// This is a deprecated API and file, so removing this to reduce errors
71+
// on our servers.
72+
// checkVersion(slug, version);
7173
getVersions(slug, version);
7274

7375
/*
@@ -78,12 +80,12 @@
7880
*/
7981

8082

81-
$.ajax({
82-
url: "https://api.grokthedocs.com/static/javascript/bundle-client.js",
83-
crossDomain: true,
84-
dataType: "script",
85-
cache: true,
86-
});
83+
// $.ajax({
84+
// url: "https://api.grokthedocs.com/static/javascript/bundle-client.js",
85+
// crossDomain: true,
86+
// dataType: "script",
87+
// cache: true,
88+
// });
8789

8890

8991

readthedocs/comments/models.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ class DocumentNodeSerializer(serializers.ModelSerializer):
111111

112112
class Meta:
113113
model = DocumentNode
114+
exclude = ('')
114115

115116

116117
class NodeSnapshot(models.Model):
@@ -197,7 +198,6 @@ def perform_create(self):
197198
class ModerationActionManager(models.Model):
198199

199200
def current_approvals(self):
200-
201201
most_recent_change = self.comment.node.snapshots.latest().date
202202

203203

@@ -222,4 +222,4 @@ class ModerationActionSerializer(serializers.ModelSerializer):
222222

223223
class Meta:
224224
model = ModerationAction
225-
pass
225+
exclude = ()

readthedocs/comments/views.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ def has_node(request):
120120
@authentication_classes([UnsafeSessionAuthentication])
121121
@renderer_classes((JSONRenderer,))
122122
def add_node(request):
123-
post_data = request.DATA
123+
post_data = request.data
124124
project = Project.objects.get(slug=post_data['project'])
125125
page = post_data.get('document', '')
126126
node_hash = post_data.get('id', '')
@@ -135,7 +135,7 @@ def add_node(request):
135135
@authentication_classes([UnsafeSessionAuthentication])
136136
@renderer_classes((JSONRenderer,))
137137
def update_node(request):
138-
post_data = request.DATA
138+
post_data = request.data
139139
try:
140140
old_hash = post_data['old_hash']
141141
new_hash = post_data['new_hash']
@@ -160,7 +160,7 @@ class CommentViewSet(ModelViewSet):
160160
permission_classes = [CommentModeratorOrReadOnly, permissions.IsAuthenticatedOrReadOnly]
161161

162162
def get_queryset(self):
163-
qp = self.request.QUERY_PARAMS
163+
qp = self.request.query_params
164164
if qp.get('node'):
165165
try:
166166
node = DocumentNode.objects.from_hash(version_slug=qp['version'],
@@ -199,7 +199,7 @@ def create(self, request):
199199
@detail_route(methods=['put'])
200200
def moderate(self, request, pk):
201201
comment = self.get_object()
202-
decision = request.DATA['decision']
202+
decision = request.data['decision']
203203
moderation_action = comment.moderate(request.user, decision)
204204

205205
return Response(ModerationActionSerializer(moderation_action).data)

readthedocs/core/management/commands/update_repos.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def handle(self, *args, **options):
5656
else:
5757
p = Project.all_objects.get(slug=slug)
5858
log.info("Building %s" % p)
59-
trigger_build(project=p, force=force)
59+
trigger_build(project=p, force=force, record=record)
6060
else:
6161
if version == "all":
6262
log.info("Updating all versions")

readthedocs/core/resolver.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,17 @@ def base_resolve_path(self, project_slug, filename, version_slug=None,
5656
# Only support `/docs/project' URLs outside our normal environment. Normally
5757
# the path should always have a subdomain or CNAME domain
5858
if subdomain or cname or (self._use_subdomain()):
59-
url = '/'
59+
url = u'/'
6060
else:
61-
url = '/docs/{project_slug}/'
61+
url = u'/docs/{project_slug}/'
6262

6363
if subproject_slug:
64-
url += 'projects/{subproject_slug}/'
64+
url += u'projects/{subproject_slug}/'
6565

6666
if single_version:
67-
url += '{filename}'
67+
url += u'{filename}'
6868
else:
69-
url += '{language}/{version_slug}/{filename}'
69+
url += u'{language}/{version_slug}/{filename}'
7070

7171
return url.format(
7272
project_slug=project_slug, filename=filename,

readthedocs/core/signals.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ def decide_if_cors(sender, request, **kwargs):
2626
2727
Returns True when a request should be given CORS access.
2828
"""
29+
if 'HTTP_ORIGIN' not in request.META:
30+
return False
2931
host = urlparse(request.META['HTTP_ORIGIN']).netloc.split(':')[0]
3032
valid_url = False
3133
for url in WHITELIST_URLS:

readthedocs/core/symlink.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262

6363
from readthedocs.builds.models import Version
6464
from readthedocs.core.utils.extend import SettingsOverrideObject
65+
from readthedocs.core.utils import safe_makedirs
6566
from readthedocs.projects import constants
6667
from readthedocs.projects.models import Domain
6768
from readthedocs.projects.utils import run
@@ -100,19 +101,19 @@ def sanity_check(self):
100101
if os.path.islink(self.project_root) and not self.project.single_version:
101102
self._log("Removing single version symlink")
102103
os.unlink(self.project_root)
103-
os.makedirs(self.project_root)
104+
safe_makedirs(self.project_root)
104105
elif (self.project.single_version and
105106
not os.path.islink(self.project_root) and
106107
os.path.exists(self.project_root)):
107108
shutil.rmtree(self.project_root)
108109
elif not os.path.lexists(self.project_root):
109-
os.makedirs(self.project_root)
110+
safe_makedirs(self.project_root)
110111

111112
# CNAME root directories
112113
if not os.path.lexists(self.CNAME_ROOT):
113-
os.makedirs(self.CNAME_ROOT)
114+
safe_makedirs(self.CNAME_ROOT)
114115
if not os.path.lexists(self.PROJECT_CNAME_ROOT):
115-
os.makedirs(self.PROJECT_CNAME_ROOT)
116+
safe_makedirs(self.PROJECT_CNAME_ROOT)
116117

117118
def run(self):
118119
"""
@@ -177,7 +178,7 @@ def symlink_subprojects(self):
177178
if rels.count():
178179
# Don't creat the `projects/` directory unless subprojects exist.
179180
if not os.path.exists(self.subproject_root):
180-
os.makedirs(self.subproject_root)
181+
safe_makedirs(self.subproject_root)
181182
for rel in rels:
182183
# A mapping of slugs for the subproject URL to the actual built
183184
# documentation
@@ -194,7 +195,7 @@ def symlink_subprojects(self):
194195
)
195196
symlink_dir = os.sep.join(symlink.split(os.path.sep)[:-1])
196197
if not os.path.lexists(symlink_dir):
197-
os.makedirs(symlink_dir)
198+
safe_makedirs(symlink_dir)
198199
run('ln -nsf %s %s' % (docs_dir, symlink))
199200

200201
# Remove old symlinks
@@ -219,7 +220,7 @@ def symlink_translations(self):
219220
if os.path.islink(language_dir):
220221
os.unlink(language_dir)
221222
if not os.path.lexists(language_dir):
222-
os.makedirs(language_dir)
223+
safe_makedirs(language_dir)
223224

224225
for (language, slug) in translations.items():
225226
self._log(u"Symlinking translation: {0}->{1}".format(language, slug))
@@ -271,7 +272,7 @@ def symlink_versions(self):
271272
version_queryset = self.get_version_queryset()
272273
if version_queryset.count():
273274
if not os.path.exists(version_dir):
274-
os.makedirs(version_dir)
275+
safe_makedirs(version_dir)
275276
for version in version_queryset:
276277
self._log(u"Symlinking Version: %s" % version)
277278
symlink = os.path.join(version_dir, version.slug)

readthedocs/core/urls/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
views.random_page,
4646
name='random_page'),
4747
url(r'^random/$', views.random_page, name='random_page'),
48-
url(r'^500/$', views.divide_by_zero, name='divide_by_zero'),
4948
url((r'^wipe/(?P<project_slug>{project_slug})/'
5049
r'(?P<version_slug>{version_slug})/$'.format(**pattern_opts)),
5150
views.wipe_version,

readthedocs/core/utils/__init__.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import errno
12
import getpass
23
import logging
34
import os
@@ -153,3 +154,18 @@ def slugify(value, *args, **kwargs):
153154

154155

155156
slugify = allow_lazy(slugify, six.text_type, SafeText)
157+
158+
159+
def safe_makedirs(directory_name):
160+
"""
161+
Makedirs has an issue where it has a race condition around
162+
checking for a directory and then creating it.
163+
This catches the exception in the case where the dir already exists.
164+
"""
165+
166+
try:
167+
os.makedirs(directory_name)
168+
except OSError as e:
169+
if e.errno == errno.EEXIST:
170+
pass
171+
raise

readthedocs/core/utils/extend.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import inspect
44

55
from django.conf import settings
6-
from django.utils.module_loading import import_by_path
6+
from django.utils.module_loading import import_string
77

88

99
def get_override_class(proxy_class, default_class=None):
@@ -24,7 +24,7 @@ def get_override_class(proxy_class, default_class=None):
2424
if class_path is None and proxy_class._override_setting is not None:
2525
class_path = getattr(settings, proxy_class._override_setting, None)
2626
if class_path is not None:
27-
default_class = import_by_path(class_path)
27+
default_class = import_string(class_path)
2828
return default_class
2929

3030

0 commit comments

Comments
 (0)