def finish_build(version_pk, build_pk, hostname=None, html=False, localmedia=False, search=False, pdf=False, epub=False): """Build Finished, do house keeping bits""" version = Version.objects.get(pk=version_pk) build = Build.objects.get(pk=build_pk) if html: version.active = True version.built = True version.save() if not pdf: clear_pdf_artifacts(version) if not epub: clear_epub_artifacts(version) move_files( version_pk=version_pk, hostname=hostname, html=html, localmedia=localmedia, search=search, pdf=pdf, epub=epub, ) # Symlink project on every web broadcast(type='app', task=symlink_project, args=[version.project.pk]) # Delayed tasks update_static_metadata.delay(version.project.pk) fileify.delay(version.pk, commit=build.commit) update_search.delay(version.pk, commit=build.commit)
def project_version_detail(request, project_slug, version_slug): """Project version detail page""" project = get_object_or_404(Project.objects.for_admin_user(request.user), slug=project_slug) version = get_object_or_404( Version.objects.public(user=request.user, project=project, only_active=False), slug=version_slug) form = VersionForm(request.POST or None, instance=version) if request.method == 'POST' and form.is_valid(): version = form.save() if form.has_changed(): if 'active' in form.changed_data and version.active is False: log.info('Removing files for version %s' % version.slug) broadcast(type='app', task=tasks.clear_artifacts, args=[version.pk]) version.built = False version.save() url = reverse('project_version_list', args=[project.slug]) return HttpResponseRedirect(url) return render_to_response( 'projects/project_version_detail.html', {'form': form, 'project': project, 'version': version}, context_instance=RequestContext(request) )
def broadcast_remove_orphan_symlinks(): """ Broadcast the task ``remove_orphan_symlinks`` to all our web servers. This task is executed by CELERY BEAT. """ broadcast(type='web', task=remove_orphan_symlinks, args=[])
def project_subprojects_delete(request, project_slug, child_slug): parent = get_object_or_404(Project.objects.for_admin_user(request.user), slug=project_slug) child = get_object_or_404(Project.objects.all(), slug=child_slug) parent.remove_subproject(child) broadcast(type='app', task=tasks.symlink_subproject, args=[parent.pk]) return HttpResponseRedirect(reverse('projects_subprojects', args=[parent.slug]))
def delete(self, *args, **kwargs): # pylint: disable=arguments-differ from readthedocs.projects import tasks log.info('Removing files for version %s', self.slug) broadcast(type='app', task=tasks.clear_artifacts, args=[self.pk]) broadcast( type='app', task=tasks.symlink_project, args=[self.project.pk]) super(Version, self).delete(*args, **kwargs)
def project_subprojects(request, project_slug): """Project subprojects view and form view""" project = get_object_or_404(Project.objects.for_admin_user(request.user), slug=project_slug) form_kwargs = { 'parent': project, 'user': request.user, } if request.method == 'POST': form = SubprojectForm(request.POST, **form_kwargs) if form.is_valid(): form.save() broadcast(type='app', task=tasks.symlink_subproject, args=[project.pk]) project_dashboard = reverse( 'projects_subprojects', args=[project.slug]) return HttpResponseRedirect(project_dashboard) else: form = SubprojectForm(**form_kwargs) subprojects = project.subprojects.all() return render_to_response( 'projects/project_subprojects.html', {'form': form, 'project': project, 'subprojects': subprojects}, context_instance=RequestContext(request) )
def form_valid(self, form): broadcast( type='app', task=tasks.symlink_subproject, args=[self.get_project().pk], ) return super(ProjectRelationshipMixin, self).form_valid(form)
def handle(self, *args, **options): queryset = Project.objects.all() for p in queryset: log.info("Generating metadata for %s", p) try: broadcast(type='app', task=tasks.update_static_metadata, args=[p.pk]) except Exception: log.exception('Build failed for %s', p)
def delete(self, *args, **kwargs): # pylint: disable=arguments-differ from readthedocs.projects import tasks broadcast( type='app', task=tasks.symlink_domain, args=[self.project.pk, self.domain, True], ) super().delete(*args, **kwargs)
def save(self, *args, **kwargs): from readthedocs.projects import tasks parsed = urlparse(self.domain) if parsed.scheme or parsed.netloc: self.domain = parsed.netloc else: self.domain = parsed.path super(Domain, self).save(*args, **kwargs) broadcast(type='app', task=tasks.symlink_domain, args=[self.project.pk, self.pk])
def delete_selected_and_artifacts(self, request, queryset): """Remove HTML/etc artifacts from application instances Prior to the query delete, broadcast tasks to delete HTML artifacts from application instances. """ if request.POST.get('post'): for project in queryset: broadcast(type='app', task=remove_dir, args=[project.doc_path]) return delete_selected(self, request, queryset)
def save(self, *args, **kwargs): # pylint: disable=arguments-differ """Add permissions to the Version for all owners on save.""" from readthedocs.projects import tasks obj = super(Version, self).save(*args, **kwargs) for owner in self.project.users.all(): assign('view_version', owner, self) try: self.project.sync_supported_versions() except Exception: log.error('failed to sync supported versions', exc_info=True) broadcast(type='app', task=tasks.symlink_project, args=[self.project.pk]) return obj
def save(self, *args, **kwargs): # pylint: disable=arguments-differ """Add permissions to the Version for all owners on save.""" from readthedocs.projects import tasks obj = super().save(*args, **kwargs) for owner in self.project.users.all(): assign('view_version', owner, self) broadcast( type='app', task=tasks.symlink_project, args=[self.project.pk], ) return obj
def save(self, *args, **kwargs): # pylint: disable=arguments-differ """Add permissions to the Version for all owners on save.""" from readthedocs.projects import tasks obj = super(Version, self).save(*args, **kwargs) for owner in self.project.users.all(): assign('view_version', owner, self) try: self.project.sync_supported_versions() except Exception: log.exception('failed to sync supported versions') broadcast( type='app', task=tasks.symlink_project, args=[self.project.pk]) return obj
def save(self, *args, **kwargs): # pylint: disable=arguments-differ from readthedocs.projects import tasks parsed = urlparse(self.domain) if parsed.scheme or parsed.netloc: self.domain = parsed.netloc else: self.domain = parsed.path super().save(*args, **kwargs) broadcast( type='app', task=tasks.symlink_domain, args=[self.project.pk, self.domain], )
def save(self, *args, **kwargs): # pylint: disable=arguments-differ from readthedocs.projects import tasks parsed = urlparse(self.domain) if parsed.scheme or parsed.netloc: self.domain = parsed.netloc else: self.domain = parsed.path super(Domain, self).save(*args, **kwargs) broadcast( type='app', task=tasks.symlink_domain, args=[self.project.pk, self.pk], )
def wipe_version_via_slugs(version_slug, project_slug): """Wipes the given version of a given project.""" version = get_object_or_404( Version, slug=version_slug, project__slug=project_slug, ) del_dirs = [ os.path.join(version.project.doc_path, 'checkouts', version.slug), os.path.join(version.project.doc_path, 'envs', version.slug), os.path.join(version.project.doc_path, 'conda', version.slug), ] for del_dir in del_dirs: broadcast(type='build', task=remove_dirs, args=[(del_dir, )])
def delete(self, *args, **kwargs): # pylint: disable=arguments-differ from readthedocs.projects import tasks # Remove local FS build artifacts on the web servers broadcast( type='app', task=tasks.remove_dirs, args=[(self.doc_path, )], ) # Remove extra resources tasks.clean_project_resources(self) super().delete(*args, **kwargs)
def wipe_version_via_slugs(version_slug, project_slug): """Wipes the given version of a given project.""" version = get_object_or_404( Version, slug=version_slug, project__slug=project_slug, ) del_dirs = [ os.path.join(version.project.doc_path, 'checkouts', version.slug), os.path.join(version.project.doc_path, 'envs', version.slug), os.path.join(version.project.doc_path, 'conda', version.slug), ] for del_dir in del_dirs: broadcast(type='build', task=remove_dirs, args=[(del_dir,)])
def post(self, request, *args, **kwargs): version = self.get_object() if not version.active: version.built = False version.save() broadcast( type='app', task=tasks.remove_dirs, args=[version.get_artifact_paths()], ) else: return HttpResponseBadRequest( "Can't delete HTML for an active version.", ) return HttpResponseRedirect(self.get_success_url())
def update_app_instances( self, html=False, localmedia=False, search=False, pdf=False, epub=False, ): """ Update application instances with build artifacts. This triggers updates across application instances for html, pdf, epub, downloads, and search. Tasks are broadcast to all web servers from here. """ # Update version if we have successfully built HTML output try: if html: version = api_v2.version(self.version.pk) version.patch({ 'built': True, }) except HttpClientError: log.exception( 'Updating version failed, skipping file sync: version=%s', self.version, ) # Broadcast finalization steps to web application instances broadcast( type='app', task=sync_files, args=[ self.project.pk, self.version.pk, self.config.doctype, ], kwargs=dict( hostname=socket.gethostname(), html=html, localmedia=localmedia, search=search, pdf=pdf, epub=epub, ), callback=sync_callback.s( version_pk=self.version.pk, commit=self.build['commit'], search=search, ), )
def save(self, *args, **kwargs): # pylint: disable=arguments-differ from readthedocs.projects import tasks first_save = self.pk is None if not self.slug: # Subdomains can't have underscores in them. self.slug = slugify(self.name) if self.slug == '': raise Exception(_('Model must have slug')) super(Project, self).save(*args, **kwargs) for owner in self.users.all(): assign('view_project', owner, self) try: if self.default_branch: latest = self.versions.get(slug=LATEST) if latest.identifier != self.default_branch: latest.identifier = self.default_branch latest.save() except Exception: log.exception('Failed to update latest identifier') # Add exceptions here for safety try: self.sync_supported_versions() except Exception: log.exception('failed to sync supported versions') try: if not first_save: broadcast( type='app', task=tasks.symlink_project, args=[self.pk], ) except Exception: log.exception('failed to symlink project') try: if not first_save: broadcast( type='app', task=tasks.update_static_metadata, args=[self.pk], ) except Exception: log.exception('failed to update static metadata') try: branch = self.default_branch or self.vcs_repo().fallback_branch if not self.versions.filter(slug=LATEST).exists(): self.versions.create_latest(identifier=branch) except Exception: log.exception('Error creating default branches')
def update_app_instances(self, html=False, localmedia=False, search=False, pdf=False, epub=False): """Update application instances with build artifacts This triggers updates across application instances for html, pdf, epub, downloads, and search. Tasks are broadcast to all web servers from here. """ # Update version if we have successfully built HTML output try: if html: version = api_v2.version(self.version.pk) version.patch({ 'active': True, 'built': True, }) except HttpClientError as e: log.error( 'Updating version failed, skipping file sync: version=%s', self.version.pk, exc_info=True) else: # Broadcast finalization steps to web application instances broadcast(type='app', task=sync_files, args=[ self.project.pk, self.version.pk, ], kwargs=dict( hostname=socket.gethostname(), html=html, localmedia=localmedia, search=search, pdf=pdf, epub=epub, )) # Delayed tasks # TODO these should be chained on to the broadcast calls. The # broadcast calls could be lumped together into a promise, and on # task result, these next few tasks can be updated, also in a # chained fashion fileify.delay(self.version.pk, commit=self.build.get('commit')) update_search.delay(self.version.pk, commit=self.build.get('commit'))
def delete_selected_and_artifacts(self, request, queryset): """ Remove HTML/etc artifacts from application instances. Prior to the query delete, broadcast tasks to delete HTML artifacts from application instances. """ if request.POST.get('post'): for project in queryset: broadcast( type='app', task=remove_dirs, args=[(project.doc_path, )], ) return delete_selected(self, request, queryset)
def delete(self, *args, **kwargs): # pylint: disable=arguments-differ from readthedocs.projects import tasks log.info('Removing files for version %s', self.slug) broadcast( type='app', task=tasks.remove_dirs, args=[self.get_artifact_paths()], ) project_pk = self.project.pk super().delete(*args, **kwargs) broadcast( type='app', task=tasks.symlink_project, args=[project_pk], )
def delete(self, *args, **kwargs): # pylint: disable=arguments-differ from readthedocs.projects import tasks log.info('Removing files for version %s', self.slug) broadcast( type='app', task=tasks.remove_dirs, args=[self.get_artifact_paths()], ) project_pk = self.project.pk super(Version, self).delete(*args, **kwargs) broadcast( type='app', task=tasks.symlink_project, args=[project_pk], )
def form_valid(self, form): version = form.save() if form.has_changed(): if 'active' in form.changed_data and version.active is False: log.info('Removing files for version %s', version.slug) broadcast( type='app', task=tasks.remove_dirs, args=[version.get_artifact_paths()], ) tasks.clean_project_resources( version.project, version, ) version.built = False version.save() return HttpResponseRedirect(self.get_success_url())
def wipe_version(request, project_slug, version_slug): version = get_object_or_404(Version, project__slug=project_slug, slug=version_slug) if request.user not in version.project.users.all(): raise Http404("You must own this project to wipe it.") if request.method == 'POST': del_dirs = [ os.path.join(version.project.doc_path, 'checkouts', version.slug), os.path.join(version.project.doc_path, 'envs', version.slug), os.path.join(version.project.doc_path, 'conda', version.slug), ] for del_dir in del_dirs: broadcast(type='build', task=remove_dir, args=[del_dir]) return redirect('project_version_list', project_slug) return render_to_response('wipe_version.html', context_instance=RequestContext(request))
def finish_build(version_pk, build_pk, hostname=None, html=False, localmedia=False, search=False, pdf=False, epub=False): """Build Finished, do house keeping bits""" version = Version.objects.get(pk=version_pk) build = Build.objects.get(pk=build_pk) if html: version.active = True version.built = True version.save() if not pdf: broadcast(type='app', task=clear_pdf_artifacts, args=[version.pk]) if not epub: broadcast(type='app', task=clear_epub_artifacts, args=[version.pk]) # Sync files to the web servers broadcast(type='app', task=move_files, args=[version_pk, hostname], kwargs=dict( html=html, localmedia=localmedia, search=search, pdf=pdf, epub=epub, )) # Symlink project on every web broadcast(type='app', task=symlink_project, args=[version.project.pk]) # Update metadata broadcast(type='app', task=update_static_metadata, args=[version.project.pk]) # Delayed tasks fileify.delay(version.pk, commit=build.commit) update_search.delay(version.pk, commit=build.commit)
def project_delete(request, project_slug): """ Project delete confirmation view. Make a project as deleted on POST, otherwise show a form asking for confirmation of delete. """ project = get_object_or_404( Project.objects.for_admin_user(request.user), slug=project_slug) if request.method == 'POST': broadcast(type='app', task=tasks.remove_dir, args=[project.doc_path]) project.delete() messages.success(request, _('Project deleted')) project_dashboard = reverse('projects_dashboard') return HttpResponseRedirect(project_dashboard) return render(request, 'projects/project_delete.html', {'project': project})
def wipe_version(request, project_slug, version_slug): version = get_object_or_404(Version, project__slug=project_slug, slug=version_slug) if request.user not in version.project.users.all(): raise Http404("You must own this project to wipe it.") if request.method == 'POST': del_dirs = [ os.path.join(version.project.doc_path, 'checkouts', version.slug), os.path.join(version.project.doc_path, 'envs', version.slug), os.path.join(version.project.doc_path, 'conda', version.slug), ] for del_dir in del_dirs: broadcast(type='build', task=remove_dir, args=[del_dir]) return redirect('project_version_list', project_slug) else: return render_to_response('wipe_version.html', context_instance=RequestContext(request))
def project_version_delete_html(request, project_slug, version_slug): """Project version 'delete' HTML This marks a version as not built """ project = get_object_or_404(Project.objects.for_admin_user(request.user), slug=project_slug) version = get_object_or_404( Version.objects.public(user=request.user, project=project, only_active=False), slug=version_slug) if not version.active: version.built = False version.save() broadcast(type='app', task=tasks.clear_artifacts, args=[version.pk]) else: return HttpResponseBadRequest("Can't delete HTML for an active version.") return HttpResponseRedirect( reverse('project_version_list', kwargs={'project_slug': project_slug}))
def wipe_version_via_slugs(version_slug, project_slug): """Wipes the given version of a given project.""" version = get_object_or_404( Version, slug=version_slug, project__slug=project_slug, ) del_dirs = [ os.path.join(version.project.doc_path, 'checkouts', version.slug), os.path.join(version.project.doc_path, 'envs', version.slug), os.path.join(version.project.doc_path, 'conda', version.slug), os.path.join(version.project.doc_path, '.cache'), ] for del_dir in del_dirs: broadcast(type='build', task=remove_dirs, args=[(del_dir, )]) # Delete the cache environment from storage build_environment_storage.delete( version.get_storage_environment_cache_path())
def delete(self, *args, **kwargs): # pylint: disable=arguments-differ from readthedocs.projects import tasks log.info('Removing files for version %s', self.slug) broadcast( type='app', task=tasks.remove_dirs, args=[self.get_artifact_paths()], ) # Remove resources if the version is not external if self.type != EXTERNAL: tasks.clean_project_resources(self.project, self) project_pk = self.project.pk super().delete(*args, **kwargs) broadcast( type='app', task=tasks.symlink_project, args=[project_pk], )
def delete(self, *args, **kwargs): # pylint: disable=arguments-differ from readthedocs.projects import tasks # Remove local FS build artifacts on the web servers broadcast( type='app', task=tasks.remove_dirs, args=[(self.doc_path, )], ) # Remove build artifacts from storage storage_paths = [] for type_ in MEDIA_TYPES: storage_paths.append('{}/{}'.format( type_, self.slug, )) tasks.remove_build_storage_paths.delay(storage_paths) super().delete(*args, **kwargs)
def save(self, *args, **kwargs): # pylint: disable=arguments-differ from readthedocs.projects import tasks first_save = self.pk is None if not self.slug: # Subdomains can't have underscores in them. self.slug = slugify(self.name) if self.slug == '': raise Exception(_("Model must have slug")) super(Project, self).save(*args, **kwargs) for owner in self.users.all(): assign('view_project', owner, self) try: if self.default_branch: latest = self.versions.get(slug=LATEST) if latest.identifier != self.default_branch: latest.identifier = self.default_branch latest.save() except Exception: log.exception('Failed to update latest identifier') # Add exceptions here for safety try: self.sync_supported_versions() except Exception: log.exception('failed to sync supported versions') try: if not first_save: broadcast(type='app', task=tasks.symlink_project, args=[self.pk]) except Exception: log.exception('failed to symlink project') try: if not first_save: broadcast(type='app', task=tasks.update_static_metadata, args=[self.pk]) except Exception: log.exception('failed to update static metadata') try: branch = self.default_branch or self.vcs_repo().fallback_branch if not self.versions.filter(slug=LATEST).exists(): self.versions.create_latest(identifier=branch) except Exception: log.exception('Error creating default branches')
def save(self, *args, **kwargs): from readthedocs.projects import tasks first_save = self.pk is None if not self.slug: # Subdomains can't have underscores in them. self.slug = slugify(self.name).replace("_", "-") if self.slug == "": raise Exception(_("Model must have slug")) super(Project, self).save(*args, **kwargs) for owner in self.users.all(): assign("view_project", owner, self) try: if self.default_branch: latest = self.versions.get(slug=LATEST) if latest.identifier != self.default_branch: latest.identifier = self.default_branch latest.save() except Exception: log.error("Failed to update latest identifier", exc_info=True) # Add exceptions here for safety try: self.sync_supported_versions() except Exception: log.error("failed to sync supported versions", exc_info=True) try: if not first_save: broadcast(type="app", task=tasks.symlink_project, args=[self.pk]) except Exception: log.error("failed to symlink project", exc_info=True) try: update_static_metadata(project_pk=self.pk) except Exception: log.error("failed to update static metadata", exc_info=True) try: branch = self.default_branch or self.vcs_repo().fallback_branch if not self.versions.filter(slug=LATEST).exists(): self.versions.create_latest(identifier=branch) except Exception: log.error("Error creating default branches", exc_info=True)
def project_version_detail(request, project_slug, version_slug): """Project version detail page.""" project = get_object_or_404( Project.objects.for_admin_user(request.user), slug=project_slug, ) version = get_object_or_404( Version.objects.public( user=request.user, project=project, only_active=False, ), slug=version_slug, ) form = VersionForm(request.POST or None, instance=version) if request.method == 'POST' and form.is_valid(): version = form.save() if form.has_changed(): if 'active' in form.changed_data and version.active is False: log.info('Removing files for version %s', version.slug) broadcast( type='app', task=tasks.remove_dirs, args=[version.get_artifact_paths()], ) version.built = False version.save() url = reverse('project_version_list', args=[project.slug]) return HttpResponseRedirect(url) return render( request, 'projects/project_version_detail.html', { 'form': form, 'project': project, 'version': version }, )
def update_app_instances(self, html=False, localmedia=False, search=False, pdf=False, epub=False): """ Update application instances with build artifacts. This triggers updates across application instances for html, pdf, epub, downloads, and search. Tasks are broadcast to all web servers from here. """ # Update version if we have successfully built HTML output try: if html: version = api_v2.version(self.version.pk) version.patch({ 'active': True, 'built': True, }) except HttpClientError: log.exception( 'Updating version failed, skipping file sync: version=%s', self.version, ) # Broadcast finalization steps to web application instances broadcast( type='app', task=sync_files, args=[ self.project.pk, self.version.pk, ], kwargs=dict( hostname=socket.gethostname(), html=html, localmedia=localmedia, search=search, pdf=pdf, epub=epub, ), callback=sync_callback.s(version_pk=self.version.pk, commit=self.build['commit']), )
def save(self, *args, **kwargs): # pylint: disable=arguments-differ from readthedocs.projects import tasks first_save = self.pk is None if not self.slug: # Subdomains can't have underscores in them. self.slug = slugify(self.name) if not self.slug: raise Exception(_('Model must have slug')) super().save(*args, **kwargs) for owner in self.users.all(): assign('view_project', owner, self) try: latest = self.versions.filter(slug=LATEST).first() default_branch = self.get_default_branch() if latest and latest.identifier != default_branch: latest.identifier = default_branch latest.save() except Exception: log.exception('Failed to update latest identifier') try: if not first_save: log.info( 'Re-symlinking project and subprojects: project=%s', self.slug, ) broadcast( type='app', task=tasks.symlink_project, args=[self.pk], ) log.info( 'Re-symlinking superprojects: project=%s', self.slug, ) for relationship in self.superprojects.all(): broadcast( type='app', task=tasks.symlink_project, args=[relationship.parent.pk], ) except Exception: log.exception('failed to symlink project') try: if not first_save: broadcast( type='app', task=tasks.update_static_metadata, args=[self.pk], ) except Exception: log.exception('failed to update static metadata') try: branch = self.default_branch or self.vcs_repo().fallback_branch if not self.versions.filter(slug=LATEST).exists(): self.versions.create_latest(identifier=branch) except Exception: log.exception('Error creating default branches')
def wipe_version(request, project_slug, version_slug): version = get_object_or_404( Version, project__slug=project_slug, slug=version_slug, ) if request.user not in version.project.users.all(): raise Http404('You must own this project to wipe it.') if request.method == 'POST': del_dirs = [ os.path.join(version.project.doc_path, 'checkouts', version.slug), os.path.join(version.project.doc_path, 'envs', version.slug), os.path.join(version.project.doc_path, 'conda', version.slug), ] for del_dir in del_dirs: broadcast(type='build', task=remove_dir, args=[del_dir]) return redirect('project_version_list', project_slug) return render(request, 'wipe_version.html', { 'version': version, 'project': version.project })
def build_docs_html(self): """Build HTML docs.""" html_builder = get_builder_class(self.project.documentation_type)( build_env=self.build_env, python_env=self.python_env, ) if self.build_force: html_builder.force() html_builder.append_conf() success = html_builder.build() if success: html_builder.move() # Gracefully attempt to move files via task on web workers. try: broadcast(type='app', task=move_files, args=[self.version.pk, socket.gethostname()], kwargs=dict(html=True) ) except socket.error: log.exception('move_files task has failed on socket error.') return success
def wipe_version(request, project_slug, version_slug): version = get_object_or_404( Version, project__slug=project_slug, slug=version_slug, ) # We need to check by ``for_admin_user`` here to allow members of the # ``Admin`` team (which doesn't own the project) under the corporate site. if version.project not in Project.objects.for_admin_user(user=request.user): raise Http404('You must own this project to wipe it.') if request.method == 'POST': del_dirs = [ os.path.join(version.project.doc_path, 'checkouts', version.slug), os.path.join(version.project.doc_path, 'envs', version.slug), os.path.join(version.project.doc_path, 'conda', version.slug), ] for del_dir in del_dirs: broadcast(type='build', task=remove_dir, args=[del_dir]) return redirect('project_version_list', project_slug) return render( request, 'wipe_version.html', {'version': version, 'project': version.project})
def delete(self, *args, **kwargs): from readthedocs.projects import tasks broadcast(type='app', task=tasks.symlink_domain, args=[self.project.pk, self.pk, True]) super(Domain, self).delete(*args, **kwargs)
def delete(self, *args, **kwargs): from readthedocs.projects import tasks log.info('Removing files for version %s' % self.slug) tasks.clear_artifacts.delay(version_pk=self.pk) broadcast(type='app', task=tasks.symlink_project, args=[self.project.pk]) super(Version, self).delete(*args, **kwargs)
def delete(self, *args, **kwargs): # pylint: disable=arguments-differ from readthedocs.projects import tasks broadcast(type='app', task=tasks.symlink_domain, args=[self.project.pk, self.pk, True]) super(Domain, self).delete(*args, **kwargs)
def save(self, *args, **kwargs): # pylint: disable=arguments-differ from readthedocs.projects import tasks first_save = self.pk is None if not self.slug: # Subdomains can't have underscores in them. self.slug = slugify(self.name) if not self.slug: raise Exception(_('Model must have slug')) if self.documentation_type == 'auto': # This used to determine the type and automatically set the # documentation type to Sphinx for rST and Mkdocs for markdown. # It now just forces Sphinx, due to markdown support. self.documentation_type = 'sphinx' super(Project, self).save(*args, **kwargs) for owner in self.users.all(): assign('view_project', owner, self) try: latest = self.versions.filter(slug=LATEST).first() default_branch = self.get_default_branch() if latest and latest.identifier != default_branch: latest.identifier = default_branch latest.save() except Exception: log.exception('Failed to update latest identifier') # Add exceptions here for safety try: self.sync_supported_versions() except Exception: log.exception('failed to sync supported versions') try: if not first_save: log.info( 'Re-symlinking project and subprojects: project=%s', self.slug, ) broadcast( type='app', task=tasks.symlink_project, args=[self.pk], ) log.info( 'Re-symlinking superprojects: project=%s', self.slug, ) for relationship in self.superprojects.all(): broadcast( type='app', task=tasks.symlink_project, args=[relationship.parent.pk], ) except Exception: log.exception('failed to symlink project') try: if not first_save: broadcast( type='app', task=tasks.update_static_metadata, args=[self.pk], ) except Exception: log.exception('failed to update static metadata') try: branch = self.default_branch or self.vcs_repo().fallback_branch if not self.versions.filter(slug=LATEST).exists(): self.versions.create_latest(identifier=branch) except Exception: log.exception('Error creating default branches')
def form_valid(self, form): broadcast(type='app', task=tasks.symlink_subproject, args=[self.get_project().pk]) return super(ProjectRelationshipMixin, self).form_valid(form)