Skip to content

Commit 33afb6c

Browse files
authored
devops: separate wheels for OS/drivers (microsoft#119)
1 parent 5076dab commit 33afb6c

File tree

8 files changed

+102
-47
lines changed

8 files changed

+102
-47
lines changed

.github/workflows/ci.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ jobs:
3131
- name: Test Sync generation script
3232
run: bash buildbots/test-sync-generation.sh
3333
build:
34+
name: Build
3435
timeout-minutes: 30
3536
strategy:
3637
fail-fast: false
@@ -87,3 +88,29 @@ jobs:
8788
path: junit/test-results-${{ matrix.os }}-${{ matrix.python-version }}-${{ matrix.browser }}.xml
8889
# Use always() to always run this step to publish test results when there are test failures
8990
if: ${{ always() }}
91+
test-package-installations:
92+
name: Test package installations
93+
runs-on: ubuntu-latest
94+
timeout-minutes: 30
95+
steps:
96+
- uses: actions/checkout@v2
97+
- uses: microsoft/playwright-github-action@v1
98+
- name: Set up Node.js
99+
uses: actions/setup-node@v1
100+
with:
101+
node-version: 12.x
102+
- name: Set up Python
103+
uses: actions/setup-python@v2
104+
with:
105+
python-version: 3.8
106+
- name: Install dependencies
107+
run: |
108+
python -m pip install --upgrade pip
109+
pip install -r local-requirements.txt
110+
pip install -e .
111+
- name: Build driver
112+
run: python build_driver.py
113+
- name: Build package
114+
run: python build_package.py
115+
- name: Test package installation
116+
run: bash buildbots/test-package-installations.sh

MANIFEST.in

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
1-
recursive-include playwright/drivers *
1+
include playwright/drivers/browsers.json
2+
include playwright/*.py
3+
include README.md
4+
include SECURITY.md
5+
include LICENSE

build_driver.py

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
import gzip
1615
import os
1716
import re
1817
import shutil
@@ -33,17 +32,8 @@
3332
if (driver_path / "out").exists():
3433
shutil.rmtree(driver_path / "out")
3534

36-
subprocess.run("npm i", cwd=driver_path, shell=True)
37-
subprocess.run("npm run bake", cwd=driver_path, shell=True)
38-
39-
for driver in ["driver-linux", "driver-macos", "driver-win.exe"]:
40-
if (package_path / driver).exists():
41-
os.remove((package_path / driver))
42-
43-
in_path = driver_path / "out" / driver
44-
out_path = drivers_path / (driver + ".gz")
45-
with open(in_path, "rb") as f_in, gzip.open(out_path, "wb") as f_out:
46-
shutil.copyfileobj(f_in, f_out)
35+
subprocess.check_call("npm i", cwd=driver_path, shell=True)
36+
subprocess.check_call("npm run bake", cwd=driver_path, shell=True)
4737

4838
node_modules_playwright = driver_path / "node_modules" / "playwright"
4939

build_package.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,11 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
import glob
16+
import os
1517
import shutil
1618
import subprocess
19+
import zipfile
1720

1821
from playwright.path_utils import get_file_dirname
1922

@@ -28,4 +31,24 @@
2831
if _egg_dir.exists():
2932
shutil.rmtree(_egg_dir)
3033

31-
subprocess.run("python setup.py sdist bdist_wheel", shell=True)
34+
subprocess.check_call("python setup.py sdist bdist_wheel", shell=True)
35+
36+
base_wheel_location = glob.glob("dist/*.whl")[0]
37+
without_platform = base_wheel_location[:-7]
38+
39+
pack_wheel_drivers = [
40+
("driver-linux", "manylinux1_x86_64.whl"),
41+
("driver-macos", "macosx_10_13_x86_64.whl"),
42+
("driver-win.exe", "win_amd64.whl"),
43+
]
44+
45+
for driver, wheel in pack_wheel_drivers:
46+
wheel_location = without_platform + wheel
47+
shutil.copy(base_wheel_location, wheel_location)
48+
from_location = f"driver/out/{driver}"
49+
to_location = f"playwright/drivers/{driver}"
50+
with zipfile.ZipFile(wheel_location, "a") as zipf:
51+
zipf.write(from_location, to_location)
52+
# for local development
53+
shutil.copy(from_location, to_location)
54+
os.remove(base_wheel_location)

buildbots/assets/stub.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from playwright import sync_playwright
2+
3+
with sync_playwright() as p:
4+
for browser_type in [p.chromium, p.firefox, p.webkit]:
5+
browser = browser_type.launch()
6+
page = browser.newPage()
7+
page.setContent("<h1>Test 123</h1>")
8+
page.screenshot(path=f"{browser_type.name}.png")
9+
browser.close()
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/bin/bash
2+
3+
tmpdir=$(mktemp -d)
4+
base_dir=$(pwd)
5+
set -e
6+
7+
# Cleanup to ensure we start fresh
8+
echo "Deleting driver and browsers from base installation"
9+
rm -rf driver
10+
rm -rf playwright
11+
rm -rf ~/.cache/ms-playwright
12+
13+
cp buildbots/assets/stub.py "$tmpdir/main.py"
14+
15+
cd $tmpdir
16+
echo "Creating virtual environment"
17+
virtualenv env
18+
source env/bin/activate
19+
echo "Installing Playwright Python via Wheel"
20+
pip install "$(echo $base_dir/dist/playwright*manylinux1*.whl)"
21+
echo "Installing browsers"
22+
python -m playwright install
23+
echo "Running basic tests"
24+
python "main.py"
25+
cd -
26+
27+
test -f "$tmpdir/chromium.png"
28+
test -f "$tmpdir/firefox.png"
29+
test -f "$tmpdir/webkit.png"
30+
echo "Passed package installation tests successfully"

driver/main.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const path = require('path');
1818

1919
(async() => {
2020
if (process.argv.includes('install')) {
21-
await require('playwright/lib/install/installer').installBrowsersWithProgressBar(path.join(path.dirname(process.argv[0]), 'drivers'));
21+
await require('playwright/lib/install/installer').installBrowsersWithProgressBar(path.dirname(process.argv[0]));
2222
return;
2323
}
2424

playwright/main.py

Lines changed: 4 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@
1313
# limitations under the License.
1414

1515
import asyncio
16-
import gzip
17-
import os
18-
import shutil
19-
import stat
2016
import subprocess
2117
import sys
2218
from typing import Any
@@ -25,7 +21,7 @@
2521

2622
from playwright.async_api import Playwright as AsyncPlaywright
2723
from playwright.connection import Connection
28-
from playwright.helper import Error, not_installed_error
24+
from playwright.helper import Error
2925
from playwright.object_factory import create_remote_object
3026
from playwright.path_utils import get_file_dirname
3127
from playwright.playwright import Playwright
@@ -47,15 +43,7 @@ def compute_driver_name() -> str:
4743
async def run_driver_async() -> Connection:
4844
package_path = get_file_dirname()
4945
driver_name = compute_driver_name()
50-
driver_executable = package_path / driver_name
51-
archive_name = package_path / "drivers" / (driver_name + ".gz")
52-
53-
if not driver_executable.exists() or os.path.getmtime(
54-
driver_executable
55-
) < os.path.getmtime(archive_name):
56-
raise not_installed_error(
57-
"Playwright requires additional post-installation step to be made."
58-
)
46+
driver_executable = package_path / "drivers" / driver_name
5947

6048
proc = await asyncio.create_subprocess_exec(
6149
str(driver_executable),
@@ -127,24 +115,8 @@ def main() -> None:
127115
return
128116
package_path = get_file_dirname()
129117
driver_name = compute_driver_name()
130-
driver_executable = package_path / driver_name
131-
archive_name = package_path / "drivers" / (driver_name + ".gz")
132-
133-
if not driver_executable.exists() or os.path.getmtime(
134-
driver_executable
135-
) < os.path.getmtime(archive_name):
136-
print(f"Extracting {archive_name} into {driver_executable}...")
137-
with gzip.open(archive_name, "rb") as f_in, open(
138-
driver_executable, "wb"
139-
) as f_out:
140-
shutil.copyfileobj(f_in, f_out)
141-
142-
st = os.stat(driver_executable)
143-
if st.st_mode & stat.S_IEXEC == 0:
144-
print(f"Making {driver_executable} executable...")
145-
os.chmod(driver_executable, st.st_mode | stat.S_IEXEC)
146-
118+
driver_executable = package_path / "drivers" / driver_name
147119
print("Installing the browsers...")
148-
subprocess.run(f"{driver_executable} install", shell=True)
120+
subprocess.check_call(f"{driver_executable} install", shell=True)
149121

150122
print("Playwright is now ready for use")

0 commit comments

Comments
 (0)