Skip to content

Commit 21bc59d

Browse files
authored
handle more edge cases for archives (#36)
1 parent efe32a5 commit 21bc59d

File tree

21 files changed

+2140
-243
lines changed

21 files changed

+2140
-243
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ concurrency:
1414
env:
1515
PYTHONUNBUFFERED: 1
1616
PIP_DISABLE_PIP_VERSION_CHECK: 1
17-
CACHE_EPOCH: 6
18-
URLJSF_PIXI_VERSION: 0.39.2
17+
CACHE_EPOCH: 7
18+
URLJSF_PIXI_VERSION: 0.39.3
1919

2020
jobs:
2121
build:

.github/workflows/pages.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ permissions:
1111
env:
1212
PYTHONUNBUFFERED: '1'
1313
PIP_DISABLE_PIP_VERSION_CHECK: '1'
14-
URLJSF_PIXI_VERSION: 0.39.2
14+
URLJSF_PIXI_VERSION: 0.39.3
1515

1616
jobs:
1717
build:

CHANGELOG.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,20 @@
33
<details>
44
<summary>Unreleased</summary>
55

6-
## 0.1.5
7-
86
> TBD
97
108
</details>
119

10+
## 0.1.5
11+
12+
- [#36]
13+
- adds support for binary files, e.g. uploaded images, in `to_zip_url` template filter
14+
- `to_zip_url` accepts a `name` parameter, to encode into the Data URL
15+
- adds `data_url_file` and `data_url_mime` to extract the file name/MIME type from a
16+
Data URL
17+
18+
[#36]: https://github.com/deathbeds/urljsf/pull/36
19+
1220
## 0.1.4
1321

1422
- [#33]

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,21 +36,21 @@
3636

3737
Once the data is _validated_, the user sees a button which gets a URL, which can be:
3838

39-
- downloaded as a file
39+
- downloaded as a file (including `.zip` archives)
4040
- opened in a new browser window
4141
- copy and pasted
4242
- submitted to an HTTP endpoint, either by opening a new window, or directly.
43-
- open native applications like email
43+
- opened in registered native applications like email
4444

4545
`urljsf` **doesn't** ship a server, so that part is up to you!
4646

47-
**Site builders** write TOML, JSON, YAML or python, then can use `urljsf` as:
47+
**Builders** write TOML, JSON, YAML, or python, then can use `urljsf` as:
4848

4949
- a drop-in-and-pray [`script`](#js-script)
5050
- a standalone [CLI tool](#command-line)
5151
- a [`sphinx`](#sphinx) or [`mkdocs`](#mkdocs) extension
5252

53-
... to create JavaScript/HTML forms that helps **visitors** provide good data for:
53+
... to create JavaScript/HTML forms that help **visitors** provide good data for:
5454

5555
- pull requests
5656
- issues

atest/libraries/archive.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""Archive keywords for ``urljsf`` acceptance tests."""
2+
# Copyright (C) urljsf contributors.
3+
# Distributed under the terms of the Modified BSD License.
4+
5+
from __future__ import annotations
6+
7+
import zipfile
8+
from pathlib import Path
9+
from urllib.request import urlopen
10+
11+
from robot.libraries.BuiltIn import BuiltIn
12+
13+
14+
def file_in_archive_url_should_match(
15+
data_url: str, member: str, path: str, msg: str | None = None
16+
) -> None:
17+
"""Verify bytes of a file contained in a zip archive match a file on disk."""
18+
bi = BuiltIn()
19+
bi.should_start_with(data_url, "data:", msg="not a Data URL")
20+
21+
with urlopen(data_url) as response, zipfile.ZipFile(response) as zf: # noqa: S310
22+
files = sorted([i.filename for i in zf.filelist])
23+
bi.log(f"files: {files}", level="ERROR")
24+
bi.should_not_be_empty(files)
25+
member_bytes = zf.read(member)
26+
bi.should_be_equal(member_bytes, Path(path).read_bytes(), msg=msg)

atest/libraries/server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""Acceptance tests for ``urljsf``."""
1+
"""Keywords for HTTP serving ``urljsf`` acceptance tests."""
22
# Copyright (C) urljsf contributors.
33
# Distributed under the terms of the Modified BSD License.
44

atest/suites/01_docs/002_installer.robot

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Library Collections
77
Library OperatingSystem
88
Library SeleniumLibrary
99
Library urllib.parse
10+
Library ../../libraries/archive.py
1011

1112
Suite Setup Setup Urljsf Suite 01_docs/002_installer
1213
Test Setup Open Sphinx Demo installer
@@ -32,6 +33,8 @@ Create An Installer Pixi Project
3233
Make And Fix A Channel Error
3334
Verify Installer URL
3435
Verify Installer Download
36+
Verify Installer Archive icon.png
37+
Verify Installer Archive icon.svg
3538

3639

3740
*** Keywords ***
@@ -103,3 +106,14 @@ Verify Installer Download
103106
${expected} = Get TOML Fixture 002_installer.toml
104107
Should Be JSON Equivalent ${from_toml} ${expected} Downloaded TOML not as expected
105108
[Teardown] Remove File ${pt}
109+
110+
Verify Installer Archive
111+
[Documentation] Verify the archive downloads correctly
112+
[Arguments] ${icon}
113+
${icon_file} = Set Variable ${ROOT}${/}docs${/}_static${/}${icon}
114+
Choose File css:#urljsf-0-pixi_icon ${icon_file}
115+
Wait Until Page Contains ${icon}
116+
${url} = Get Element Attribute xpath://pre[3] textContent
117+
${url} = Set Variable ${url.strip()[4:]}
118+
File In Archive URL Should Match ${url} ${icon} ${icon_file}
119+
... Icon did not match

docs/.readthedocs.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ build:
66
# `mambaforge-latest` will now start failing: we just need a working `mamba`
77
python: mambaforge-23.11
88
commands:
9-
- mamba install -c conda-forge -c nodefaults pixi==0.39.2
9+
- mamba install -c conda-forge -c nodefaults pixi==0.39.3
1010
- pixi r build-yarn
1111
- pixi r build
1212
- pixi r dist-npm

docs/_static/icon.png

1.37 KB
Loading

docs/demos.py

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"https://raw.githubusercontent.com/spdx/license-list-data/refs/heads/main/"
3131
f"json/{LICENSES.name}"
3232
),
33-
REAL_PIXI_SCHEMA: ("https://pixi.sh/v0.39.2/schema/manifest/schema.json",),
33+
REAL_PIXI_SCHEMA: ("https://pixi.sh/v0.39.3/schema/manifest/schema.json",),
3434
}
3535

3636
FALLBACKS: dict[Path, dict[str, Any]] = {
@@ -292,6 +292,11 @@ def installer() -> Urljsf:
292292
"items": {"$ref": "#/definitions/a-pixi-package-def"},
293293
"minLength": 1,
294294
},
295+
"icon": {
296+
"description": "an icon in SVG, PNG",
297+
"type": "string",
298+
"format": "data-url",
299+
},
295300
},
296301
"definitions": {
297302
"a-subdir": {"type": "string", "enum": subdirs},
@@ -321,6 +326,7 @@ def installer() -> Urljsf:
321326
"platforms",
322327
"channels",
323328
"dependencies",
329+
"icon",
324330
]
325331
},
326332
"channels": {"items": {"ui:options": {"label": False}}},
@@ -343,6 +349,11 @@ def installer() -> Urljsf:
343349
},
344350
}
345351
},
352+
"icon": {
353+
"ui:options": {
354+
"accept": ".png,.svg",
355+
}
356+
},
346357
}
347358

348359
pixi_form_data = {
@@ -373,22 +384,32 @@ def installer() -> Urljsf:
373384

374385
toml_template = """
375386
{% macro pixi_toml(p, schema=None) %}
387+
376388
{% set deps = [] %}
389+
377390
{% for dep in p.dependencies %}
378391
{% set e = dep.spec %}
379392
{% if dep.channel %}
380393
{% set e = {"version": dep.spec, "channel": dep.channel } %}
381394
{% endif %}
382395
{% set deps = (deps.push([dep.package, e]), deps) %}
383396
{% endfor %}
397+
398+
{% set tool = {} %}
399+
400+
{% if data.pixi.icon %}
401+
{% set tool = {"icon": data.pixi.icon} %}
402+
{% endif %}
403+
384404
{% set PT = {
385405
"project": {
386406
"name": p.name,
387407
"version": p.version,
388408
"platforms": p.platforms,
389409
"channels": p.channels
390410
},
391-
"dependencies": (deps | from_entries)
411+
"dependencies": (deps | from_entries),
412+
"tool": tool
392413
} | prune %}
393414
{% if schema %}
394415
{% for err in PT | schema_errors(schema) %}
@@ -417,24 +438,36 @@ def installer() -> Urljsf:
417438
data:application/toml,{{ t | urlencode }}
418439
```
419440
420-
421-
_As a `.zip` archive (with a `.gitignore` file and `README.md` and
422-
`pull_request_template.md`):_
441+
{%- set files = [
442+
["pixi.toml", t],
443+
["README.md", "# " ~ data.pixi.name],
444+
[".gitignore", ".pixi"],
445+
[".github", {
446+
"pull_request_template.md": [
447+
"thanks for contributing to " ~ data.pixi.name,
448+
{"level": 9}
449+
]
450+
}]
451+
] -%}
452+
453+
_As a `.zip` archive with:_
454+
- the `pixi.toml`
455+
- a `.gitignore` file
456+
- a `README.md`
457+
- a `.github/pull_request_template.md`
458+
{%- if data.pixi.icon -%}
459+
{%- set regExp = r/name=(.*?);/ -%}
460+
{%- set icon = data.pixi.icon | data_url_file -%}
461+
{%- set files = (files.push([icon, data.pixi.icon]), files) %}
462+
- `{{ icon }}`, an icon `{{ data.pixi.icon | data_url_mime }}` file)
463+
{%- endif %}
423464
424465
```
425466
{{
426-
{
427-
"pixi.toml": t,
428-
"README.md": "# " ~ data.pixi.name,
429-
".gitignore": ".pixi",
430-
".github": {
431-
"pull_request_template.md": [
432-
"thanks for contributing to " ~ data.pixi.name,
433-
{"level": 9}
434-
]
435-
}
436-
}
437-
| to_zip_url(level=0)
467+
files
468+
| from_entries
469+
| prune
470+
| to_zip_url(level=0, name=data.pixi.name ~ ".zip")
438471
}}
439472
```
440473
"""

0 commit comments

Comments
 (0)