Skip to content

Commit 601a3bc

Browse files
committed
Merge branch 'master' of https://github.com/rtfd/readthedocs.org into feature/remove_filters
2 parents a79eaec + e92c3f5 commit 601a3bc

File tree

12 files changed

+85
-24
lines changed

12 files changed

+85
-24
lines changed

docs/ethical-advertising.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ However,
99
instead of using Google,
1010
we are building the advertising model that we want to exist.
1111
We only work with companies we like and respect,
12-
and offer products that are relevent to developers
13-
We hope that you'll discover new products and services that are relvent,
12+
and offer products that are relevant to developers.
13+
We hope that you'll discover new products and services that are relevant,
1414
and also new companies that care about supporting the open source community.
1515

1616
**We're building an advertising model that respects users while providing value to advertisers.**

prospector-more.yml

-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ ignore-paths:
66
- core/
77
- doc_builder/
88
- donate/
9-
- projects/
10-
- redirects/
119
- restapi/
1210
- search/
1311

readthedocs/projects/forms.py

+3
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,9 @@ def save(self, **_):
515515

516516

517517
class DomainForm(forms.ModelForm):
518+
519+
"""Form to configure a custom domain name for a project."""
520+
518521
project = forms.CharField(widget=forms.HiddenInput(), required=False)
519522

520523
class Meta:

readthedocs/projects/models.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
from django.conf import settings
99
from django.contrib.auth.models import User
10-
from django.core.exceptions import MultipleObjectsReturned
1110
from django.core.urlresolvers import reverse, NoReverseMatch
1211
from django.db import models
1312
from django.utils.translation import ugettext_lazy as _
@@ -877,6 +876,9 @@ def __unicode__(self):
877876

878877

879878
class Domain(models.Model):
879+
880+
"""A custom domain name for a project."""
881+
880882
project = models.ForeignKey(Project, related_name='domains')
881883
domain = models.CharField(_('Domain'), unique=True, max_length=255,
882884
validators=[validate_domain_name])

readthedocs/projects/tasks.py

+41-10
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,8 @@ def _log(self, msg):
107107
version=self.version.slug,
108108
msg=msg))
109109

110-
def run(self, pk, version_pk=None, build_pk=None, record=True, docker=False,
111-
search=True, force=False, localmedia=True, **kwargs):
110+
def run(self, pk, version_pk=None, build_pk=None, record=True,
111+
docker=False, search=True, force=False, localmedia=True, **__):
112112

113113
self.project = self.get_project(pk)
114114
self.version = self.get_version(self.project, version_pk)
@@ -118,9 +118,22 @@ def run(self, pk, version_pk=None, build_pk=None, record=True, docker=False,
118118
self.build_force = force
119119
self.config = None
120120

121-
env_cls = LocalEnvironment
122-
self.setup_env = env_cls(project=self.project, version=self.version,
123-
build=self.build, record=record)
121+
setup_successful = self.run_setup(record=record)
122+
if setup_successful:
123+
self.run_build(record=record, docker=docker)
124+
125+
def run_setup(self, record=True):
126+
"""Run setup in the local environment.
127+
128+
Return True if successful.
129+
130+
"""
131+
self.setup_env = LocalEnvironment(
132+
project=self.project,
133+
version=self.version,
134+
build=self.build,
135+
record=record
136+
)
124137

125138
# Environment used for code checkout & initial configuration reading
126139
with self.setup_env:
@@ -145,16 +158,34 @@ def run(self, pk, version_pk=None, build_pk=None, record=True, docker=False,
145158

146159
if self.setup_env.failure or self.config is None:
147160
self._log('Failing build because of setup failure: %s' % self.setup_env.failure)
148-
self.send_notifications()
161+
162+
# Send notification to users only if the build didn't fail because of
163+
# LockTimeout: this exception occurs when a build is triggered before the previous
164+
# one has finished (e.g. two webhooks, one after the other)
165+
if not isinstance(self.setup_env.failure, vcs_support_utils.LockTimeout):
166+
self.send_notifications()
167+
149168
self.setup_env.update_build(state=BUILD_STATE_FINISHED)
150-
return None
169+
return False
151170

152171
if self.setup_env.successful and not self.project.has_valid_clone:
153172
self.set_valid_clone()
154173

174+
return True
175+
176+
def run_build(self, docker=False, record=True):
177+
"""Build the docs in an environment.
178+
179+
If `docker` is True, or Docker is enabled by the settings.DOCKER_ENABLE
180+
setting, then build in a Docker environment. Otherwise build locally.
181+
182+
"""
155183
env_vars = self.get_env_vars()
184+
156185
if docker or settings.DOCKER_ENABLE:
157186
env_cls = DockerEnvironment
187+
else:
188+
env_cls = LocalEnvironment
158189
self.build_env = env_cls(project=self.project, version=self.version,
159190
build=self.build, record=record, environment=env_vars)
160191

@@ -502,7 +533,7 @@ def update_imported_docs(version_pk):
502533
try:
503534
api_v2.project(project.pk).sync_versions.post(version_post_data)
504535
except HttpClientError as e:
505-
log.error("Sync Versions Exception: %s" % e.content)
536+
log.error("Sync Versions Exception: %s", e.content)
506537
except Exception as e:
507538
log.error("Unknown Sync Versions Exception", exc_info=True)
508539
return ret_dict
@@ -740,8 +771,8 @@ def _manage_imported_files(version, path, commit):
740771
).exclude(commit=commit).delete()
741772
# Purge Cache
742773
changed_files = [resolve_path(
743-
version.project, filename=file, version_slug=version.slug,
744-
) for file in changed_files]
774+
version.project, filename=fname, version_slug=version.slug,
775+
) for fname in changed_files]
745776
cdn_ids = getattr(settings, 'CDN_IDS', None)
746777
if cdn_ids:
747778
if version.project.slug in cdn_ids:

readthedocs/projects/views/base.py

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
"""Mix-in classes for project views."""
12
import logging
23
from datetime import datetime, timedelta
34

readthedocs/projects/views/private.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from django.contrib.auth.decorators import login_required
66
from django.contrib.auth.models import User
77
from django.contrib import messages
8-
from django.contrib.contenttypes.models import ContentType
98
from django.core.urlresolvers import reverse
109
from django.http import (HttpResponseRedirect, HttpResponseNotAllowed,
1110
Http404, HttpResponseBadRequest)
@@ -172,7 +171,7 @@ def project_version_detail(request, project_slug, version_slug):
172171
version = form.save()
173172
if form.has_changed():
174173
if 'active' in form.changed_data and version.active is False:
175-
log.info('Removing files for version %s' % version.slug)
174+
log.info('Removing files for version %s', version.slug)
176175
broadcast(type='app', task=tasks.clear_artifacts, args=[version.pk])
177176
version.built = False
178177
version.save()

readthedocs/projects/views/public.py

-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
from django.template import RequestContext
1818
from django.views.decorators.cache import cache_control
1919
from django.views.generic import ListView, DetailView
20-
from django.views.decorators.cache import cache_page
2120

2221
from taggit.models import Tag
2322
import requests

readthedocs/redirects/admin.py

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""Django admin configuration for the redirects app."""
2+
13
from __future__ import absolute_import
24

35
from django.contrib import admin

readthedocs/redirects/managers.py

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""Manager and queryset for the redirects app."""
2+
13
from django.db.models import Manager
24
from django.db.models.query import QuerySet
35

readthedocs/redirects/models.py

+11-6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""Django models for the redirects app."""
2+
13
from django.db import models
24
from django.utils.translation import ugettext
35
from django.utils.translation import ugettext_lazy as _
@@ -41,6 +43,9 @@
4143

4244

4345
class Redirect(models.Model):
46+
47+
"""A HTTP redirect associated with a Project."""
48+
4449
project = models.ForeignKey(Project, verbose_name=_('Project'),
4550
related_name='redirects')
4651

@@ -101,7 +106,7 @@ def get_redirect_path(self, path, language=None, version_slug=None):
101106

102107
def redirect_prefix(self, path, language=None, version_slug=None):
103108
if path.startswith(self.from_url):
104-
log.debug('Redirecting %s' % self)
109+
log.debug('Redirecting %s', self)
105110
cut_path = re.sub('^%s' % self.from_url, '', path)
106111
to = self.get_full_path(
107112
filename=cut_path,
@@ -111,16 +116,16 @@ def redirect_prefix(self, path, language=None, version_slug=None):
111116

112117
def redirect_page(self, path, language=None, version_slug=None):
113118
if path == self.from_url:
114-
log.debug('Redirecting %s' % self)
119+
log.debug('Redirecting %s', self)
115120
to = self.get_full_path(
116121
filename=self.to_url.lstrip('/'),
117122
language=language,
118123
version_slug=version_slug)
119124
return to
120125

121-
def redirect_exact(self, path, language=None, version_slug=None):
126+
def redirect_exact(self, path, **__):
122127
if path == self.from_url:
123-
log.debug('Redirecting %s' % self)
128+
log.debug('Redirecting %s', self)
124129
return self.to_url
125130
# Handle full sub-level redirects
126131
if '$rest' in self.from_url:
@@ -132,7 +137,7 @@ def redirect_exact(self, path, language=None, version_slug=None):
132137
def redirect_sphinx_html(self, path, language=None, version_slug=None):
133138
for ending in ['/', '/index.html']:
134139
if path.endswith(ending):
135-
log.debug('Redirecting %s' % self)
140+
log.debug('Redirecting %s', self)
136141
path = path[1:] # Strip leading slash.
137142
to = re.sub(ending + '$', '.html', path)
138143
return self.get_full_path(
@@ -142,7 +147,7 @@ def redirect_sphinx_html(self, path, language=None, version_slug=None):
142147

143148
def redirect_sphinx_htmldir(self, path, language=None, version_slug=None):
144149
if path.endswith('.html'):
145-
log.debug('Redirecting %s' % self)
150+
log.debug('Redirecting %s', self)
146151
path = path[1:] # Strip leading slash.
147152
to = re.sub('.html$', '/', path)
148153
return self.get_full_path(

readthedocs/redirects/utils.py

+19
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
"""Redirection view support.
2+
3+
This module allows for parsing a URL path, looking up redirects associated
4+
with it in the database, and generating a redirect response.
5+
6+
These are not used directly as views; they are instead included into 404
7+
handlers, so that redirects only take effect if no other view matches.
8+
9+
"""
110
from django.http import HttpResponseRedirect
211
import logging
312
import re
@@ -10,6 +19,16 @@
1019

1120

1221
def project_and_path_from_request(request, path):
22+
"""Parse the project from a request path.
23+
24+
Return a tuple (project, path) where `project` is a projects.Project if
25+
a matching project exists, and `path` is the unmatched remainder of the
26+
path.
27+
28+
If the path does not match, or no matching project is found, then `project`
29+
will be ``None``.
30+
31+
"""
1332
if hasattr(request, 'slug'):
1433
project_slug = request.slug
1534
elif path.startswith('/docs/'):

0 commit comments

Comments
 (0)