Skip to content

Commit

Permalink
Added utility to export assets manually
Browse files Browse the repository at this point in the history
- Added tests for utility
  • Loading branch information
llacroix committed Mar 2, 2023
1 parent ef45d68 commit 2fa9dd0
Show file tree
Hide file tree
Showing 4 changed files with 250 additions and 0 deletions.
33 changes: 33 additions & 0 deletions odoo_tools/cli/click/manage.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import re
import click
import logging
from pathlib import Path

from .utils import MODULE_TYPE
from ...configuration.misc import DictObject
from ...modules.assets import AssetsBundler


_logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -48,6 +50,37 @@ def update(ctx, database, modules):
return True


@manage.command(
help="Build Asset"
)
@click.option(
'-d',
'--database',
help="Database"
)
@click.option(
'--minified',
is_flag=True,
default=False
)
@click.argument("type")
@click.argument("asset")
@click.pass_context
def asset(ctx, database, asset, type, minified):
env = ctx.obj['env']
env.check_odoo()
manage = env.manage.db(database)
manage.default_entrypoints()

with manage.env() as oenv:
bundler = AssetsBundler(oenv, asset)

if type == 'css':
print(bundler.get_css(minified))
elif type == 'js':
print(bundler.get_js(minified))


@manage.command(
help="Install modules in the provided database"
)
Expand Down
68 changes: 68 additions & 0 deletions odoo_tools/modules/assets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import re


class AssetsBundler(object):
def __init__(self, env, asset):
self.env = env
self.asset = asset
self._bundle = None

@property
def bundle(self):
if not self._bundle:
self._bundle = self.get_bundle()

return self._bundle

def get_bundle(self):
from odoo.addons.base.models.assetsbundle import AssetsBundle
self.files = self.get_files()
return AssetsBundle(self.asset, self.files[0], env=self.env)

def get_files(self):
qweb = self.env['ir.qweb']
files = qweb._get_asset_content(self.asset)
return files

def get_js(self, minified=False):
result = []

if minified:
for js in self.bundle.javascripts:
result.append(f"{js.minify()};")
else:
for js in self.bundle.javascripts:
result.append(js.with_header(js.content, minimal=False))

return "\n".join(result)

def get_css(self, minified=False):
from odoo.addons.base.models.assetsbundle import AssetsBundle

data = self.bundle.preprocess_css()

matches = []
data = re.sub(
AssetsBundle.rx_css_import,
lambda matchobj: matches.append(matchobj.group(0)) and '',
data
)

if minified:
matches.append(data)
else:
for style in self.bundle.stylesheets:
if not style.content:
continue

content = style.with_header(style.content)

content = re.sub(
AssetsBundle.rx_css_import,
lambda matchobj: f"/* {matchobj.group(0)} */",
content
)

matches.append(content)

return "\n".join(matches)
45 changes: 45 additions & 0 deletions tests/cli/test_manage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from mock import patch, MagicMock
from odoo_tools.cli.odot import command
from odoo_tools.api.environment import Environment


def test_bundler(runner):

def fake_check_odoo(self):
self.manage = MagicMock()

obj_path = 'odoo_tools.cli.click.manage.AssetsBundler'

with patch(obj_path) as bundler, \
patch.object(Environment, 'check_odoo', autospec=True) as check_odoo:

bun_instance = MagicMock()
bundler.return_value = bun_instance

check_odoo.side_effect = fake_check_odoo
# manage.return_value = MagicMock()

result = runner.invoke(
command,
[
'manage',
'asset',
'css',
'base.common',
]
)

assert result.exception is None
bun_instance.get_css.assert_called_once()
bun_instance.get_js.assert_not_called()

result = runner.invoke(
command,
[
'manage',
'asset',
'js',
'base.common',
]
)
bun_instance.get_js.assert_called_once()
104 changes: 104 additions & 0 deletions tests/modules/test_assets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import re

import pytest
from mock import MagicMock, patch

from odoo_tools.modules.assets import AssetsBundler


@pytest.fixture
def modules():
odoo = MagicMock()

models = odoo.addons.base.models

return {
"odoo": odoo,
"odoo.addons": odoo.addons,
"odoo.addons.base": odoo.addons.base,
"odoo.addons.base.models": odoo.addons.base.models,
"odoo.addons.base.models.assetsbundle": models.assetsbundle,
}


class MockAsset(object):
def __init__(self, name, data):
self.name = name
self.content = data

def with_header(self, content, minimal=False):
return f"/* {self.name} */\n{content}"

def minify(self):
return f"minified {self.content}"


class MockBundle(object):
rx_css_import = r".*"

def __init__(self, asset, file, env=None):
self.asset = asset
self.file = file
self.env = env

self.javascripts = [
MockAsset("f1", "a"),
MockAsset("f2", "b")
]

self.stylesheets = [
MockAsset('c1', 'c'),
MockAsset('c2', 'd'),
MockAsset('c2', ''),
]

def preprocess_css(self):
result = ["prep"]

for asset in self.stylesheets:
result.append(asset.content)
if asset.content != '':
asset.content = 'm'

return "\n".join(result)


def test_assets_bundler(modules):
asset = 'base.common'
env = MagicMock()

bundler = AssetsBundler(env, asset)
assert bundler.env == env
assert bundler.asset == asset
assert bundler._bundle is None

bundle_path = "odoo.addons.base.models.assetsbundle.AssetsBundle"

with patch.dict('sys.modules', modules), \
patch(bundle_path, MockBundle):
assert isinstance(bundler.bundle, MockBundle)
assert bundler._bundle is not None

js = bundler.get_js()
assert js == '/* f1 */\na\n/* f2 */\nb'

js_minified = bundler.get_js(minified=True)
assert js_minified == 'minified a;\nminified b;'

# output with headers but output not relevant, it's
# just mocked to confirm different outputs
bundler = AssetsBundler(env, asset)
css = bundler.get_css()
assert css == (
'prep\n\n'
'c\n\nd\n\n\n'
'/* /* c1 */ *//* */\n'
'/* m *//* */\n'
'/* /* c2 */ *//* */\n'
'/* m *//* */'
)

# raw output from preprocess and matches
bundler = AssetsBundler(env, asset)
css_minified = bundler.get_css(minified=True)
assert css_minified == 'prep\n\nc\n\nd\n\n\n\n\n\n'

0 comments on commit 2fa9dd0

Please sign in to comment.