Skip to content

Commit

Permalink
Fix a bug where extensions using npm would have their caches leak bet…
Browse files Browse the repository at this point in the history
…ween different sites. (bartfeenstra#934)
  • Loading branch information
bartfeenstra authored Dec 6, 2022
1 parent fc80f3d commit 8c7c7c7
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 2 deletions.
7 changes: 7 additions & 0 deletions betty/cache.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging
import shutil
from contextlib import suppress
from enum import unique, IntFlag, auto
from typing import TYPE_CHECKING

from betty import fs
Expand All @@ -9,6 +10,12 @@
from betty.builtins import _


@unique
class CacheScope(IntFlag):
BETTY = auto()
PROJECT = auto()


async def clear():
with suppress(FileNotFoundError):
shutil.rmtree(fs.CACHE_DIRECTORY_PATH)
Expand Down
5 changes: 5 additions & 0 deletions betty/http_api_doc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from shutil import copy2
from typing import Optional, Set, Type, TYPE_CHECKING

from betty.cache import CacheScope

if TYPE_CHECKING:
from betty.builtins import _
Expand All @@ -22,6 +23,10 @@ async def npm_build(self, working_directory_path: Path, assets_directory_path: P
copy2(working_directory_path / 'node_modules' / 'redoc' / 'bundles' / 'redoc.standalone.js', assets_directory_path / 'http-api-doc.js')
logging.getLogger().info('Built the HTTP API documentation.')

@classmethod
def npm_cache_scope(cls) -> CacheScope:
return CacheScope.BETTY

async def generate(self) -> None:
assets_directory_path = await self.app.extensions[_Npm].ensure_assets(self)
copy2(assets_directory_path / 'http-api-doc.js', self.app.project.configuration.www_directory_path / 'http-api-doc.js')
Expand Down
6 changes: 6 additions & 0 deletions betty/maps/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from shutil import copy2, copytree
from typing import Optional, Set, Type, TYPE_CHECKING, List

from betty.cache import CacheScope

if TYPE_CHECKING:
from betty.builtins import _

Expand All @@ -30,6 +32,10 @@ def _copy_npm_build(self, source_directory_path: Path, destination_directory_pat
with suppress(FileNotFoundError):
copytree(source_directory_path / 'images', destination_directory_path / 'images')

@classmethod
def npm_cache_scope(cls) -> CacheScope:
return CacheScope.BETTY

async def generate(self) -> None:
assets_directory_path = await self.app.extensions[_Npm].ensure_assets(self)
self._copy_npm_build(assets_directory_path, self.app.project.configuration.www_directory_path)
Expand Down
13 changes: 11 additions & 2 deletions betty/npm/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import hashlib
import logging
import os
import shutil
Expand All @@ -16,6 +17,7 @@
from betty.app.extension import Extension, discover_extension_types
from betty.app.extension.requirement import Requirement, AnyRequirement, AllRequirements
from betty.asyncio import sync
from betty.cache import CacheScope

if TYPE_CHECKING:
from betty.builtins import _
Expand Down Expand Up @@ -105,6 +107,10 @@ class NpmBuilder:
async def npm_build(self, working_directory_path: Path, assets_directory_path: Path) -> None:
raise NotImplementedError

@classmethod
def npm_cache_scope(cls) -> CacheScope:
return CacheScope.PROJECT


def discover_npm_builders() -> Set[Type[Extension | NpmBuilder]]:
return {
Expand All @@ -115,7 +121,7 @@ def discover_npm_builders() -> Set[Type[Extension | NpmBuilder]]:
}


def _get_assets_directory_path(extension_type: Type[Extension] | Type[NpmBuilder]) -> Path:
def _get_assets_directory_path(extension_type: Type[Extension | NpmBuilder]) -> Path:
assert issubclass(extension_type, Extension)
assert issubclass(extension_type, NpmBuilder)
assets_directory_path = extension_type.assets_directory_path()
Expand Down Expand Up @@ -185,7 +191,10 @@ async def install(self, extension_type: Type[Extension | NpmBuilder], working_di

def _get_cached_assets_build_directory_path(self, extension_type: Type[Extension | NpmBuilder]) -> Path:
assert issubclass(extension_type, Extension) and issubclass(extension_type, NpmBuilder)
return self.cache_directory_path / extension_type.name()
path = self.cache_directory_path / extension_type.name()
if extension_type.npm_cache_scope() == CacheScope.PROJECT:
path /= hashlib.md5(str(self.app.project.configuration.configuration_file_path).encode('utf-8')).hexdigest()
return path

async def ensure_assets(self, extension: Extension | NpmBuilder) -> Path:
assets_build_directory_paths = [
Expand Down
6 changes: 6 additions & 0 deletions betty/trees/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from shutil import copy2
from typing import Optional, Set, Type, List, TYPE_CHECKING

from betty.cache import CacheScope

if TYPE_CHECKING:
from betty.builtins import _

Expand All @@ -28,6 +30,10 @@ def _copy_npm_build(self, source_directory_path: Path, destination_directory_pat
copy2(source_directory_path / 'trees.css', destination_directory_path / 'trees.css')
copy2(source_directory_path / 'trees.js', destination_directory_path / 'trees.js')

@classmethod
def npm_cache_scope(cls) -> CacheScope:
return CacheScope.BETTY

async def generate(self) -> None:
assets_directory_path = await self.app.extensions[_Npm].ensure_assets(self)
self._copy_npm_build(assets_directory_path, self.app.project.configuration.www_directory_path)
Expand Down

0 comments on commit 8c7c7c7

Please sign in to comment.