Skip to content

Commit 74d5d2c

Browse files
committed
Ensure npm install runs once at a time
On starting up the Lektor server, the server_spawn and before_build_all events both fire, each one spawning `npm install`. This ensures that only one runs at a time.
1 parent 677c839 commit 74d5d2c

File tree

2 files changed

+25
-1
lines changed

2 files changed

+25
-1
lines changed

lektor_webpack_support.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
import threading
23

34
from lektor.pluginsystem import Plugin
45
from lektor.reporter import reporter
@@ -11,6 +12,7 @@ class WebpackSupportPlugin(Plugin):
1112

1213
def __init__(self, *args, **kwargs):
1314
Plugin.__init__(self, *args, **kwargs)
15+
self.npm_lock = threading.Lock()
1416
self.webpack_process = None
1517

1618
def is_enabled(self, extra_flags):
@@ -26,7 +28,11 @@ def run_webpack(self, watch=False):
2628
def npm_install(self):
2729
reporter.report_generic('Running npm install')
2830
webpack_root = os.path.join(self.env.root_path, 'webpack')
29-
portable_popen(['npm', 'install'], cwd=webpack_root).wait()
31+
if self.npm_lock.acquire(False):
32+
portable_popen(['npm', 'install'], cwd=webpack_root).wait()
33+
else:
34+
self.npm_lock.acquire()
35+
self.npm_lock.release()
3036

3137
def on_server_spawn(self, **extra):
3238
extra_flags = extra.get("extra_flags") or extra.get("build_flags") or {}

tests/test_plugin.py

+18
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import py
2+
import threading
3+
import time
24

35

46
def test_disabled_by_default(plugin):
@@ -66,3 +68,19 @@ def test_server_stop(plugin, mocker):
6668
plugin.webpack_process = mocker.Mock()
6769
plugin.on_server_stop()
6870
plugin.webpack_process.kill.assert_called_with()
71+
72+
73+
def test_single_npm_process(plugin, builder, mocker):
74+
def pause(*args, **kwargs):
75+
time.sleep(.1)
76+
return mocker.DEFAULT
77+
78+
mock_popen = mocker.patch("lektor_webpack_support.portable_popen")
79+
mock_popen.side_effect = pause
80+
thread1 = threading.Thread(target=plugin.npm_install)
81+
thread2 = threading.Thread(target=plugin.npm_install)
82+
thread1.start()
83+
thread2.start()
84+
thread1.join()
85+
thread2.join()
86+
assert mock_popen.call_count == 1

0 commit comments

Comments
 (0)