From a1810fa1523c52fee359ddc0ec1441463de41d3c Mon Sep 17 00:00:00 2001 From: alexsilva Date: Thu, 11 Jul 2019 15:33:25 -0300 Subject: [PATCH 01/27] App app settings. --- npm/__init__.py | 1 + npm/apps.py | 10 ++++++++++ npm/finders.py | 11 ++++++++--- npm/management/commands/npm_install.py | 1 + 4 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 npm/apps.py diff --git a/npm/__init__.py b/npm/__init__.py index e69de29..7b1b5a6 100644 --- a/npm/__init__.py +++ b/npm/__init__.py @@ -0,0 +1 @@ +default_app_config = 'npm.apps.NPMConfig' diff --git a/npm/apps.py b/npm/apps.py new file mode 100644 index 0000000..b119c50 --- /dev/null +++ b/npm/apps.py @@ -0,0 +1,10 @@ +from django.apps import AppConfig +from django.conf import settings + + +class NPMConfig(AppConfig): + name = 'npm' + verbose_name = "NPM package installer" + + # app settings + NPM_EXECUTABLE_PATH = getattr(settings, 'NPM_EXECUTABLE_PATH', 'npm') diff --git a/npm/finders.py b/npm/finders.py index 2746bef..ca8d912 100644 --- a/npm/finders.py +++ b/npm/finders.py @@ -2,20 +2,25 @@ import subprocess from fnmatch import fnmatch +from django.apps import apps +from django.conf import settings from django.contrib.staticfiles import utils as django_utils from django.contrib.staticfiles.finders import FileSystemFinder from django.core.files.storage import FileSystemStorage -from django.conf import settings try: from collections import OrderedDict except ImportError: from ordereddict import OrderedDict +app = apps.get_app_config("npm") + + +def npm_install(**config): + npm_executable_path = config.setdefault('npm_executable_path', app.NPM_EXECUTABLE_PATH) -def npm_install(): - npm_executable_path = getattr(settings, 'NPM_EXECUTABLE_PATH', 'npm') command = [npm_executable_path, 'install', '--prefix=' + get_npm_root_path()] + proc = subprocess.Popen( command, env={'PATH': os.environ.get('PATH')}, diff --git a/npm/management/commands/npm_install.py b/npm/management/commands/npm_install.py index 9550baf..96d0a5e 100644 --- a/npm/management/commands/npm_install.py +++ b/npm/management/commands/npm_install.py @@ -1,4 +1,5 @@ from django.core.management.base import BaseCommand + from npm.finders import npm_install From c71ed67670aaedf82ba6f6bb8cd191a69d8b03b9 Mon Sep 17 00:00:00 2001 From: alexsilva Date: Thu, 11 Jul 2019 15:38:02 -0300 Subject: [PATCH 02/27] Add NPM_ROOT_PATH app config. --- npm/apps.py | 3 +++ npm/finders.py | 8 ++------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/npm/apps.py b/npm/apps.py index b119c50..dfeb400 100644 --- a/npm/apps.py +++ b/npm/apps.py @@ -1,3 +1,5 @@ +import os + from django.apps import AppConfig from django.conf import settings @@ -8,3 +10,4 @@ class NPMConfig(AppConfig): # app settings NPM_EXECUTABLE_PATH = getattr(settings, 'NPM_EXECUTABLE_PATH', 'npm') + NPM_ROOT_PATH = getattr(settings, 'NPM_ROOT_PATH', os.getcwd()) diff --git a/npm/finders.py b/npm/finders.py index ca8d912..017c434 100644 --- a/npm/finders.py +++ b/npm/finders.py @@ -19,7 +19,7 @@ def npm_install(**config): npm_executable_path = config.setdefault('npm_executable_path', app.NPM_EXECUTABLE_PATH) - command = [npm_executable_path, 'install', '--prefix=' + get_npm_root_path()] + command = [npm_executable_path, 'install', '--prefix=' + app.NPM_ROOT_PATH] proc = subprocess.Popen( command, @@ -28,10 +28,6 @@ def npm_install(**config): proc.wait() -def get_npm_root_path(): - return getattr(settings, 'NPM_ROOT_PATH', '.') - - def flatten_patterns(patterns): if patterns is None: return None @@ -84,7 +80,7 @@ def get_files(storage, match_patterns='*', ignore_patterns=None, location=''): class NpmFinder(FileSystemFinder): def __init__(self, apps=None, *args, **kwargs): - self.node_modules_path = get_npm_root_path() + self.node_modules_path = app.NPM_ROOT_PATH self.destination = getattr(settings, 'NPM_STATIC_FILES_PREFIX', '') self.cache_enabled = getattr(settings, 'NPM_FINDER_USE_CACHE', True) self.cached_list = None From 12e5bea42b3c1e05da63aef34325be7eb0b7d67e Mon Sep 17 00:00:00 2001 From: alexsilva Date: Fri, 12 Jul 2019 13:26:51 -0300 Subject: [PATCH 03/27] Fix windows issues. --- npm/finders.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/npm/finders.py b/npm/finders.py index 017c434..30ae681 100644 --- a/npm/finders.py +++ b/npm/finders.py @@ -1,4 +1,5 @@ import os +import shlex import subprocess from fnmatch import fnmatch @@ -7,6 +8,7 @@ from django.contrib.staticfiles import utils as django_utils from django.contrib.staticfiles.finders import FileSystemFinder from django.core.files.storage import FileSystemStorage +from django.utils.six import string_types try: from collections import OrderedDict @@ -17,9 +19,20 @@ def npm_install(**config): - npm_executable_path = config.setdefault('npm_executable_path', app.NPM_EXECUTABLE_PATH) + """ + Windows settings + node_executable = "D:\\Program Files\\nodejs\\node.exe" + npm_cli = os.path.join(os.path.dirname(node_executable), + "node_modules\\npm\\bin\\npm-cli.js") + :param config: npm_executable + :return: + """ + npm_executable = config.setdefault('npm_executable', app.NPM_EXECUTABLE_PATH) + + if isinstance(npm_executable, string_types): + npm_executable = shlex.split(npm_executable) - command = [npm_executable_path, 'install', '--prefix=' + app.NPM_ROOT_PATH] + command = npm_executable + ['install', '--prefix=' + app.NPM_ROOT_PATH] proc = subprocess.Popen( command, From d2b95b8190ed4a61d578e0ff46b83ec65ca6d945 Mon Sep 17 00:00:00 2001 From: alexsilva Date: Fri, 12 Jul 2019 16:45:41 -0300 Subject: [PATCH 04/27] Better command. --- npm/finders.py | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/npm/finders.py b/npm/finders.py index 30ae681..918e289 100644 --- a/npm/finders.py +++ b/npm/finders.py @@ -1,14 +1,19 @@ +from __future__ import print_function + import os import shlex import subprocess +import sys from fnmatch import fnmatch +from logging import getLogger from django.apps import apps from django.conf import settings from django.contrib.staticfiles import utils as django_utils from django.contrib.staticfiles.finders import FileSystemFinder from django.core.files.storage import FileSystemStorage -from django.utils.six import string_types + +logger = getLogger(__name__) try: from collections import OrderedDict @@ -24,21 +29,29 @@ def npm_install(**config): node_executable = "D:\\Program Files\\nodejs\\node.exe" npm_cli = os.path.join(os.path.dirname(node_executable), "node_modules\\npm\\bin\\npm-cli.js") - :param config: npm_executable - :return: + NPM_EXECUTABLE_PATH = '"%s" "%s"' % (node_executable, npm_cli) """ npm_executable = config.setdefault('npm_executable', app.NPM_EXECUTABLE_PATH) + npm_workdir = config.setdefault('npm_workdir', os.getcwd()) + npm_args = config.setdefault('npm_args', ()) + + command = shlex.split(npm_executable) - if isinstance(npm_executable, string_types): - npm_executable = shlex.split(npm_executable) + if not npm_args: + command.extend(['install', '--prefix=' + app.NPM_ROOT_PATH]) - command = npm_executable + ['install', '--prefix=' + app.NPM_ROOT_PATH] + logger.debug(str(command)) proc = subprocess.Popen( command, - env={'PATH': os.environ.get('PATH')}, + env=os.environ, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + cwd=npm_workdir, + bufsize=2048 ) - proc.wait() + for data in iter(proc.stdout.readline, ''): + print(data, file=sys.stdout, end='') def flatten_patterns(patterns): From 821b5f43ae85d357e107809a4b03eae21ba2e98e Mon Sep 17 00:00:00 2001 From: alexsilva Date: Fri, 12 Jul 2019 16:56:25 -0300 Subject: [PATCH 05/27] Extends command args. --- npm/finders.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/npm/finders.py b/npm/finders.py index 918e289..1779de8 100644 --- a/npm/finders.py +++ b/npm/finders.py @@ -33,12 +33,14 @@ def npm_install(**config): """ npm_executable = config.setdefault('npm_executable', app.NPM_EXECUTABLE_PATH) npm_workdir = config.setdefault('npm_workdir', os.getcwd()) - npm_args = config.setdefault('npm_args', ()) + npm_command_args = config.setdefault('npm_command_args', ()) command = shlex.split(npm_executable) - if not npm_args: + if not npm_command_args: command.extend(['install', '--prefix=' + app.NPM_ROOT_PATH]) + else: + command.extend(npm_command_args) logger.debug(str(command)) @@ -50,8 +52,11 @@ def npm_install(**config): cwd=npm_workdir, bufsize=2048 ) - for data in iter(proc.stdout.readline, ''): - print(data, file=sys.stdout, end='') + while proc.poll() is None: + for data in iter(proc.stdout.readline, ''): + print(data, file=sys.stdout, end='') + # npm code + return proc.poll() def flatten_patterns(patterns): From 305a1b41848b29a78f15a8aa483575c51597da78 Mon Sep 17 00:00:00 2001 From: alexsilva Date: Fri, 12 Jul 2019 17:01:27 -0300 Subject: [PATCH 06/27] Move config to apps. --- npm/apps.py | 4 ++++ npm/finders.py | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/npm/apps.py b/npm/apps.py index dfeb400..1a88034 100644 --- a/npm/apps.py +++ b/npm/apps.py @@ -11,3 +11,7 @@ class NPMConfig(AppConfig): # app settings NPM_EXECUTABLE_PATH = getattr(settings, 'NPM_EXECUTABLE_PATH', 'npm') NPM_ROOT_PATH = getattr(settings, 'NPM_ROOT_PATH', os.getcwd()) + + NPM_STATIC_FILES_PREFIX = getattr(settings, 'NPM_STATIC_FILES_PREFIX', '') + NPM_FINDER_USE_CACHE = getattr(settings, 'NPM_FINDER_USE_CACHE', True) + NPM_FILE_PATTERNS = getattr(settings, 'NPM_FILE_PATTERNS', None) diff --git a/npm/finders.py b/npm/finders.py index 1779de8..f995466 100644 --- a/npm/finders.py +++ b/npm/finders.py @@ -20,7 +20,7 @@ except ImportError: from ordereddict import OrderedDict -app = apps.get_app_config("npm") +app_config = apps.get_app_config("npm") def npm_install(**config): @@ -31,14 +31,14 @@ def npm_install(**config): "node_modules\\npm\\bin\\npm-cli.js") NPM_EXECUTABLE_PATH = '"%s" "%s"' % (node_executable, npm_cli) """ - npm_executable = config.setdefault('npm_executable', app.NPM_EXECUTABLE_PATH) + npm_executable = config.setdefault('npm_executable', app_config.NPM_EXECUTABLE_PATH) npm_workdir = config.setdefault('npm_workdir', os.getcwd()) npm_command_args = config.setdefault('npm_command_args', ()) command = shlex.split(npm_executable) if not npm_command_args: - command.extend(['install', '--prefix=' + app.NPM_ROOT_PATH]) + command.extend(['install', '--prefix=' + app_config.NPM_ROOT_PATH]) else: command.extend(npm_command_args) @@ -111,12 +111,12 @@ def get_files(storage, match_patterns='*', ignore_patterns=None, location=''): class NpmFinder(FileSystemFinder): def __init__(self, apps=None, *args, **kwargs): - self.node_modules_path = app.NPM_ROOT_PATH - self.destination = getattr(settings, 'NPM_STATIC_FILES_PREFIX', '') - self.cache_enabled = getattr(settings, 'NPM_FINDER_USE_CACHE', True) + self.node_modules_path = app_config.NPM_ROOT_PATH + self.destination = app_config.NPM_STATIC_FILES_PREFIX + self.cache_enabled = app_config.NPM_FINDER_USE_CACHE self.cached_list = None - self.match_patterns = flatten_patterns(getattr(settings, 'NPM_FILE_PATTERNS', None)) or ['*'] + self.match_patterns = flatten_patterns(app_config.NPM_FILE_PATTERNS) or ['*'] self.locations = [(self.destination, os.path.join(self.node_modules_path, 'node_modules'))] self.storages = OrderedDict() From d39a71c6964752e1afecaf0bcc9ff2965c515412 Mon Sep 17 00:00:00 2001 From: alexsilva Date: Fri, 12 Jul 2019 17:04:43 -0300 Subject: [PATCH 07/27] Log command and code. --- npm/finders.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/npm/finders.py b/npm/finders.py index f995466..7a1db29 100644 --- a/npm/finders.py +++ b/npm/finders.py @@ -8,7 +8,6 @@ from logging import getLogger from django.apps import apps -from django.conf import settings from django.contrib.staticfiles import utils as django_utils from django.contrib.staticfiles.finders import FileSystemFinder from django.core.files.storage import FileSystemStorage @@ -42,8 +41,6 @@ def npm_install(**config): else: command.extend(npm_command_args) - logger.debug(str(command)) - proc = subprocess.Popen( command, env=os.environ, @@ -55,6 +52,7 @@ def npm_install(**config): while proc.poll() is None: for data in iter(proc.stdout.readline, ''): print(data, file=sys.stdout, end='') + logger.debug("%s %s" % (proc.poll(), command)) # npm code return proc.poll() From 5939dbecf27420c1dee64a8f598392c685e81fa6 Mon Sep 17 00:00:00 2001 From: alexsilva Date: Fri, 12 Jul 2019 17:15:07 -0300 Subject: [PATCH 08/27] New command. --- npm/management/commands/npm_cli.py | 15 +++++++++++++++ npm/management/commands/npm_install.py | 10 ---------- 2 files changed, 15 insertions(+), 10 deletions(-) create mode 100644 npm/management/commands/npm_cli.py delete mode 100644 npm/management/commands/npm_install.py diff --git a/npm/management/commands/npm_cli.py b/npm/management/commands/npm_cli.py new file mode 100644 index 0000000..5102afb --- /dev/null +++ b/npm/management/commands/npm_cli.py @@ -0,0 +1,15 @@ +import argparse + +from django.core.management.base import BaseCommand + +from npm.finders import npm_install + + +class Command(BaseCommand): + help = 'Run npm install' + + def add_arguments(self, parser): + parser.add_argument('npm_command_args', nargs=argparse.REMAINDER) + + def handle(self, *args, **options): + npm_install(npm_command_args=options.get('npm_command_args', ())) diff --git a/npm/management/commands/npm_install.py b/npm/management/commands/npm_install.py deleted file mode 100644 index 96d0a5e..0000000 --- a/npm/management/commands/npm_install.py +++ /dev/null @@ -1,10 +0,0 @@ -from django.core.management.base import BaseCommand - -from npm.finders import npm_install - - -class Command(BaseCommand): - help = 'Run npm install' - - def handle(self, *args, **options): - npm_install() From 69800ef4785444f7bb9779b7d6c53465b90fea3d Mon Sep 17 00:00:00 2001 From: alexsilva Date: Fri, 12 Jul 2019 17:31:44 -0300 Subject: [PATCH 09/27] No save by default. --- npm/finders.py | 1 + 1 file changed, 1 insertion(+) diff --git a/npm/finders.py b/npm/finders.py index 7a1db29..d59de27 100644 --- a/npm/finders.py +++ b/npm/finders.py @@ -40,6 +40,7 @@ def npm_install(**config): command.extend(['install', '--prefix=' + app_config.NPM_ROOT_PATH]) else: command.extend(npm_command_args) + command.extend(['--no-save']) proc = subprocess.Popen( command, From 56f56435cf70c912c6af6d345a39b0a10d46dbb1 Mon Sep 17 00:00:00 2001 From: alexsilva Date: Fri, 12 Jul 2019 18:02:22 -0300 Subject: [PATCH 10/27] Letting the user choose whether saved or not dependency. --- npm/finders.py | 1 - 1 file changed, 1 deletion(-) diff --git a/npm/finders.py b/npm/finders.py index d59de27..7a1db29 100644 --- a/npm/finders.py +++ b/npm/finders.py @@ -40,7 +40,6 @@ def npm_install(**config): command.extend(['install', '--prefix=' + app_config.NPM_ROOT_PATH]) else: command.extend(npm_command_args) - command.extend(['--no-save']) proc = subprocess.Popen( command, From 16c45159b8eb7a71b0f0a3e93194d1afc0065842 Mon Sep 17 00:00:00 2001 From: alexsilva Date: Fri, 12 Jul 2019 18:04:25 -0300 Subject: [PATCH 11/27] Move reference strings. --- npm/apps.py | 7 +++++++ npm/finders.py | 8 +------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/npm/apps.py b/npm/apps.py index 1a88034..e5f8a18 100644 --- a/npm/apps.py +++ b/npm/apps.py @@ -9,7 +9,14 @@ class NPMConfig(AppConfig): verbose_name = "NPM package installer" # app settings + + # Windows settings + # node_executable = "D:\\Program Files\\nodejs\\node.exe" + # npm_cli = os.path.join(os.path.dirname(node_executable), + # "node_modules\\npm\\bin\\npm-cli.js") + # NPM_EXECUTABLE_PATH = '"%s" "%s"' % (node_executable, npm_cli) NPM_EXECUTABLE_PATH = getattr(settings, 'NPM_EXECUTABLE_PATH', 'npm') + NPM_ROOT_PATH = getattr(settings, 'NPM_ROOT_PATH', os.getcwd()) NPM_STATIC_FILES_PREFIX = getattr(settings, 'NPM_STATIC_FILES_PREFIX', '') diff --git a/npm/finders.py b/npm/finders.py index 7a1db29..d4e21d4 100644 --- a/npm/finders.py +++ b/npm/finders.py @@ -23,13 +23,7 @@ def npm_install(**config): - """ - Windows settings - node_executable = "D:\\Program Files\\nodejs\\node.exe" - npm_cli = os.path.join(os.path.dirname(node_executable), - "node_modules\\npm\\bin\\npm-cli.js") - NPM_EXECUTABLE_PATH = '"%s" "%s"' % (node_executable, npm_cli) - """ + """Install nodejs packages""" npm_executable = config.setdefault('npm_executable', app_config.NPM_EXECUTABLE_PATH) npm_workdir = config.setdefault('npm_workdir', os.getcwd()) npm_command_args = config.setdefault('npm_command_args', ()) From 3bb515a3fd78fd57884394da5a480a34f02ee2fe Mon Sep 17 00:00:00 2001 From: alexsilva Date: Fri, 12 Jul 2019 18:05:41 -0300 Subject: [PATCH 12/27] Ignore .idea --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b1fd0a2..8f929d0 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ build/ dist/ .cache +.idea \ No newline at end of file From 549e19e16106d90b1bfcfd9f36cc12d3ca94032e Mon Sep 17 00:00:00 2001 From: alexsilva Date: Fri, 12 Jul 2019 20:40:57 -0300 Subject: [PATCH 13/27] Complete wrap. --- npm/finders.py | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/npm/finders.py b/npm/finders.py index d4e21d4..70d3ebe 100644 --- a/npm/finders.py +++ b/npm/finders.py @@ -4,6 +4,8 @@ import shlex import subprocess import sys +import threading +import time from fnmatch import fnmatch from logging import getLogger @@ -22,6 +24,28 @@ app_config = apps.get_app_config("npm") +class StdinWriter(threading.Thread): + def __init__(self, proc): + threading.Thread.__init__(self) + self.proc = proc + + def do_input(self): + data = sys.stdin.readline() + self.proc.stdin.write(data) + if not data.strip(os.linesep): + time.sleep(1) + + def run(self): + while self.proc.poll() is None: + try: + self.do_input() + except (IOError, ValueError): + break + + def close(self): + self.proc.stdin.close() + + def npm_install(**config): """Install nodejs packages""" npm_executable = config.setdefault('npm_executable', app_config.NPM_EXECUTABLE_PATH) @@ -40,12 +64,23 @@ def npm_install(**config): env=os.environ, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, + stdin=subprocess.PIPE, + universal_newlines=True, cwd=npm_workdir, bufsize=2048 ) - while proc.poll() is None: - for data in iter(proc.stdout.readline, ''): + writer = StdinWriter(proc) + writer.start() + try: + while proc.poll() is None: + data = proc.stdout.read(1) + if not data: + break print(data, file=sys.stdout, end='') + finally: + proc.stdout.close() + writer.close() + logger.debug("%s %s" % (proc.poll(), command)) # npm code return proc.poll() From 3704514d9a8e78e9c88bba82be841fbef936bffa Mon Sep 17 00:00:00 2001 From: alexsilva Date: Mon, 15 Jul 2019 10:21:13 -0300 Subject: [PATCH 14/27] Move StdinWriter to process. --- npm/finders.py | 25 +------------------------ npm/process.py | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 24 deletions(-) create mode 100644 npm/process.py diff --git a/npm/finders.py b/npm/finders.py index 70d3ebe..262f376 100644 --- a/npm/finders.py +++ b/npm/finders.py @@ -4,8 +4,6 @@ import shlex import subprocess import sys -import threading -import time from fnmatch import fnmatch from logging import getLogger @@ -13,6 +11,7 @@ from django.contrib.staticfiles import utils as django_utils from django.contrib.staticfiles.finders import FileSystemFinder from django.core.files.storage import FileSystemStorage +from npm.process import StdinWriter logger = getLogger(__name__) @@ -24,28 +23,6 @@ app_config = apps.get_app_config("npm") -class StdinWriter(threading.Thread): - def __init__(self, proc): - threading.Thread.__init__(self) - self.proc = proc - - def do_input(self): - data = sys.stdin.readline() - self.proc.stdin.write(data) - if not data.strip(os.linesep): - time.sleep(1) - - def run(self): - while self.proc.poll() is None: - try: - self.do_input() - except (IOError, ValueError): - break - - def close(self): - self.proc.stdin.close() - - def npm_install(**config): """Install nodejs packages""" npm_executable = config.setdefault('npm_executable', app_config.NPM_EXECUTABLE_PATH) diff --git a/npm/process.py b/npm/process.py new file mode 100644 index 0000000..2f4d541 --- /dev/null +++ b/npm/process.py @@ -0,0 +1,27 @@ +from __future__ import print_function + +import sys +import threading + + +class StdinWriter(threading.Thread): + """Reads stdin data and passes back to the process""" + def __init__(self, proc): + threading.Thread.__init__(self) + self.proc = proc + self.setDaemon(True) + + def do_input(self): + data = sys.stdin.readline() + self.proc.stdin.write(data) + self.proc.stdin.flush() + + def run(self): + while self.proc.poll() is None: + try: + self.do_input() + except (IOError, ValueError): + break + + def close(self): + self.proc.stdin.close() From 2f3d109310e76d49cdd16054a5b43fa6f425e200 Mon Sep 17 00:00:00 2001 From: alexsilva Date: Mon, 15 Jul 2019 10:22:36 -0300 Subject: [PATCH 15/27] Add compat module. --- npm/compat.py | 4 ++++ npm/finders.py | 7 ++----- 2 files changed, 6 insertions(+), 5 deletions(-) create mode 100644 npm/compat.py diff --git a/npm/compat.py b/npm/compat.py new file mode 100644 index 0000000..4a0702e --- /dev/null +++ b/npm/compat.py @@ -0,0 +1,4 @@ +try: + from collections import OrderedDict +except ImportError: + from ordereddict import OrderedDict diff --git a/npm/finders.py b/npm/finders.py index 262f376..501c1f8 100644 --- a/npm/finders.py +++ b/npm/finders.py @@ -11,15 +11,12 @@ from django.contrib.staticfiles import utils as django_utils from django.contrib.staticfiles.finders import FileSystemFinder from django.core.files.storage import FileSystemStorage + +from npm.compat import OrderedDict from npm.process import StdinWriter logger = getLogger(__name__) -try: - from collections import OrderedDict -except ImportError: - from ordereddict import OrderedDict - app_config = apps.get_app_config("npm") From 87f807917e9d07ada8971aefac9770ee015a0ee4 Mon Sep 17 00:00:00 2001 From: alexsilva Date: Mon, 15 Jul 2019 10:28:22 -0300 Subject: [PATCH 16/27] StdinWriter context. --- npm/finders.py | 20 +++++++++----------- npm/process.py | 7 +++++++ 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/npm/finders.py b/npm/finders.py index 501c1f8..748e480 100644 --- a/npm/finders.py +++ b/npm/finders.py @@ -43,17 +43,15 @@ def npm_install(**config): cwd=npm_workdir, bufsize=2048 ) - writer = StdinWriter(proc) - writer.start() - try: - while proc.poll() is None: - data = proc.stdout.read(1) - if not data: - break - print(data, file=sys.stdout, end='') - finally: - proc.stdout.close() - writer.close() + with StdinWriter(proc): + try: + while proc.poll() is None: + data = proc.stdout.read(1) + if not data: + break + print(data, file=sys.stdout, end='') + finally: + proc.stdout.close() logger.debug("%s %s" % (proc.poll(), command)) # npm code diff --git a/npm/process.py b/npm/process.py index 2f4d541..ede2084 100644 --- a/npm/process.py +++ b/npm/process.py @@ -25,3 +25,10 @@ def run(self): def close(self): self.proc.stdin.close() + + def __enter__(self): + self.start() + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.close() From 7b855aa121cba7310b77a742a2548881a84ece5e Mon Sep 17 00:00:00 2001 From: alexsilva Date: Mon, 15 Jul 2019 10:33:19 -0300 Subject: [PATCH 17/27] pep8 --- tests/test_finder.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/test_finder.py b/tests/test_finder.py index fcaaf43..ca1ab2f 100644 --- a/tests/test_finder.py +++ b/tests/test_finder.py @@ -1,4 +1,5 @@ from .util import configure_settings + configure_settings() import pytest @@ -28,35 +29,42 @@ def test_get_files(npm_dir): files = get_files(storage, match_patterns='*') assert any([True for _ in files]) + def test_finder_list_all(npm_dir): f = NpmFinder() assert any([True for _ in f.list()]) + def test_finder_find(npm_dir): f = NpmFinder() file = f.find('mocha/mocha.js') assert file + def test_finder_in_subdirectory(npm_dir): with override_settings(NPM_STATIC_FILES_PREFIX='lib'): f = NpmFinder() assert f.find('lib/mocha/mocha.js') + def test_finder_with_patterns_in_subdirectory(npm_dir): with override_settings(NPM_STATIC_FILES_PREFIX='lib', NPM_FILE_PATTERNS={'mocha': ['*']}): f = NpmFinder() assert f.find('lib/mocha/mocha.js') + def test_finder_with_patterns_in_directory_component(npm_dir): with override_settings(NPM_STATIC_FILES_PREFIX='lib', NPM_FILE_PATTERNS={'mocha': ['*/*js']}): f = NpmFinder() assert f.find('lib/mocha/lib/test.js') + def test_no_matching_paths_returns_empty_list(npm_dir): with override_settings(NPM_FILE_PATTERNS={'foo': ['bar']}): f = NpmFinder() assert f.find('mocha/mocha.js') == [] + def test_finder_cache(npm_dir): with override_settings(NPM_FINDER_USE_CACHE=True): f = NpmFinder() @@ -64,6 +72,7 @@ def test_finder_cache(npm_dir): assert f.cached_list is not None assert f.list() is f.cached_list + def test_finder_no_cache(npm_dir): with override_settings(NPM_FINDER_USE_CACHE=False): f = NpmFinder() From 22c5372bc051795386363b52bd05697e2a85cfc9 Mon Sep 17 00:00:00 2001 From: alexsilva Date: Mon, 15 Jul 2019 10:54:22 -0300 Subject: [PATCH 18/27] Update test; Add npm app. --- tests/util.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/util.py b/tests/util.py index b6b8455..cdf1baa 100644 --- a/tests/util.py +++ b/tests/util.py @@ -1,12 +1,15 @@ from django.conf import settings +import django def configure_settings(): settings.configure( DEBUG=True, + INSTALLED_APPS=['npm'], CACHES={ 'default': { 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', } } ) + django.setup() From 543865f2dc7d49ef8dd597b41e4dc7d0266b6c02 Mon Sep 17 00:00:00 2001 From: alexsilva Date: Mon, 15 Jul 2019 12:02:21 -0300 Subject: [PATCH 19/27] Fix app settings based tests. --- npm/apps.py | 18 ------------------ npm/conf.py | 22 ++++++++++++++++++++++ npm/finders.py | 16 +++++++--------- 3 files changed, 29 insertions(+), 27 deletions(-) create mode 100644 npm/conf.py diff --git a/npm/apps.py b/npm/apps.py index e5f8a18..7952d25 100644 --- a/npm/apps.py +++ b/npm/apps.py @@ -1,24 +1,6 @@ -import os - from django.apps import AppConfig -from django.conf import settings class NPMConfig(AppConfig): name = 'npm' verbose_name = "NPM package installer" - - # app settings - - # Windows settings - # node_executable = "D:\\Program Files\\nodejs\\node.exe" - # npm_cli = os.path.join(os.path.dirname(node_executable), - # "node_modules\\npm\\bin\\npm-cli.js") - # NPM_EXECUTABLE_PATH = '"%s" "%s"' % (node_executable, npm_cli) - NPM_EXECUTABLE_PATH = getattr(settings, 'NPM_EXECUTABLE_PATH', 'npm') - - NPM_ROOT_PATH = getattr(settings, 'NPM_ROOT_PATH', os.getcwd()) - - NPM_STATIC_FILES_PREFIX = getattr(settings, 'NPM_STATIC_FILES_PREFIX', '') - NPM_FINDER_USE_CACHE = getattr(settings, 'NPM_FINDER_USE_CACHE', True) - NPM_FILE_PATTERNS = getattr(settings, 'NPM_FILE_PATTERNS', None) diff --git a/npm/conf.py b/npm/conf.py new file mode 100644 index 0000000..134b7ec --- /dev/null +++ b/npm/conf.py @@ -0,0 +1,22 @@ +import os +from django.conf import settings +from appconf import AppConf + + +class MyAppConf(AppConf): + # app settings + + # Windows settings + # node_executable = "D:\\Program Files\\nodejs\\node.exe" + # npm_cli = os.path.join(os.path.dirname(node_executable), + # "node_modules\\npm\\bin\\npm-cli.js") + # NPM_EXECUTABLE_PATH = '"%s" "%s"' % (node_executable, npm_cli) + EXECUTABLE_PATH = 'npm' + ROOT_PATH = os.getcwd() + + STATIC_FILES_PREFIX = '' + FINDER_USE_CACHE = True + FILE_PATTERNS = None + + class Meta: + prefix = 'npm' diff --git a/npm/finders.py b/npm/finders.py index 748e480..ad34f38 100644 --- a/npm/finders.py +++ b/npm/finders.py @@ -7,29 +7,27 @@ from fnmatch import fnmatch from logging import getLogger -from django.apps import apps from django.contrib.staticfiles import utils as django_utils from django.contrib.staticfiles.finders import FileSystemFinder from django.core.files.storage import FileSystemStorage from npm.compat import OrderedDict +from npm.conf import settings from npm.process import StdinWriter logger = getLogger(__name__) -app_config = apps.get_app_config("npm") - def npm_install(**config): """Install nodejs packages""" - npm_executable = config.setdefault('npm_executable', app_config.NPM_EXECUTABLE_PATH) + npm_executable = config.setdefault('npm_executable', settings.NPM_EXECUTABLE_PATH) npm_workdir = config.setdefault('npm_workdir', os.getcwd()) npm_command_args = config.setdefault('npm_command_args', ()) command = shlex.split(npm_executable) if not npm_command_args: - command.extend(['install', '--prefix=' + app_config.NPM_ROOT_PATH]) + command.extend(['install', '--prefix=' + settings.NPM_ROOT_PATH]) else: command.extend(npm_command_args) @@ -110,12 +108,12 @@ def get_files(storage, match_patterns='*', ignore_patterns=None, location=''): class NpmFinder(FileSystemFinder): def __init__(self, apps=None, *args, **kwargs): - self.node_modules_path = app_config.NPM_ROOT_PATH - self.destination = app_config.NPM_STATIC_FILES_PREFIX - self.cache_enabled = app_config.NPM_FINDER_USE_CACHE + self.node_modules_path = settings.NPM_ROOT_PATH + self.destination = settings.NPM_STATIC_FILES_PREFIX + self.cache_enabled = settings.NPM_FINDER_USE_CACHE self.cached_list = None - self.match_patterns = flatten_patterns(app_config.NPM_FILE_PATTERNS) or ['*'] + self.match_patterns = flatten_patterns(settings.NPM_FILE_PATTERNS) or ['*'] self.locations = [(self.destination, os.path.join(self.node_modules_path, 'node_modules'))] self.storages = OrderedDict() From 300aac11db95cbd9d5535f5605199dff77e672c9 Mon Sep 17 00:00:00 2001 From: alexsilva Date: Mon, 15 Jul 2019 12:04:24 -0300 Subject: [PATCH 20/27] Set npm_workdir at NPM_ROOT_PATH. --- npm/finders.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm/finders.py b/npm/finders.py index ad34f38..2610968 100644 --- a/npm/finders.py +++ b/npm/finders.py @@ -21,7 +21,7 @@ def npm_install(**config): """Install nodejs packages""" npm_executable = config.setdefault('npm_executable', settings.NPM_EXECUTABLE_PATH) - npm_workdir = config.setdefault('npm_workdir', os.getcwd()) + npm_workdir = config.setdefault('npm_workdir', settings.NPM_ROOT_PATH) npm_command_args = config.setdefault('npm_command_args', ()) command = shlex.split(npm_executable) From ba8cae2b99cc48dc90787d989c085c2189766354 Mon Sep 17 00:00:00 2001 From: alexsilva Date: Mon, 15 Jul 2019 12:05:17 -0300 Subject: [PATCH 21/27] Add django-appconf has requirements. --- setup.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 99f987a..8dd614a 100644 --- a/setup.py +++ b/setup.py @@ -3,11 +3,12 @@ here = path.abspath(path.dirname(__file__)) +requirements = ['django-appconf'] + try: from collections import OrderedDict - requirements = [] except ImportError: - requirements = ['ordereddict'] + requirements.append('ordereddict') setup( name='django-npm', From a92d9de38afefca5a4c4a067dfb6b259655bdc9d Mon Sep 17 00:00:00 2001 From: alexsilva Date: Mon, 15 Jul 2019 12:05:57 -0300 Subject: [PATCH 22/27] Configure NPM_EXECUTABLE_PATH as environ. --- tests/util.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/util.py b/tests/util.py index cdf1baa..88e6289 100644 --- a/tests/util.py +++ b/tests/util.py @@ -1,3 +1,5 @@ +import os + from django.conf import settings import django @@ -6,6 +8,7 @@ def configure_settings(): settings.configure( DEBUG=True, INSTALLED_APPS=['npm'], + NPM_EXECUTABLE_PATH=os.environ.get('NPM_EXECUTABLE_PATH', 'npm'), CACHES={ 'default': { 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', From e767c6c6d7450d45674ef22e75590c8107ada53e Mon Sep 17 00:00:00 2001 From: alexsilva Date: Mon, 15 Jul 2019 12:51:07 -0300 Subject: [PATCH 23/27] Fix tests for windows. --- tests/test_finder.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/tests/test_finder.py b/tests/test_finder.py index ca1ab2f..3434b81 100644 --- a/tests/test_finder.py +++ b/tests/test_finder.py @@ -1,4 +1,7 @@ -from .util import configure_settings +import os +from os.path import normpath + +from tests.util import configure_settings configure_settings() @@ -37,32 +40,32 @@ def test_finder_list_all(npm_dir): def test_finder_find(npm_dir): f = NpmFinder() - file = f.find('mocha/mocha.js') + file = f.find(normpath('mocha/mocha.js')) assert file def test_finder_in_subdirectory(npm_dir): with override_settings(NPM_STATIC_FILES_PREFIX='lib'): f = NpmFinder() - assert f.find('lib/mocha/mocha.js') + assert f.find(normpath('lib/mocha/mocha.js')) def test_finder_with_patterns_in_subdirectory(npm_dir): with override_settings(NPM_STATIC_FILES_PREFIX='lib', NPM_FILE_PATTERNS={'mocha': ['*']}): f = NpmFinder() - assert f.find('lib/mocha/mocha.js') + assert f.find(normpath('lib/mocha/mocha.js')) def test_finder_with_patterns_in_directory_component(npm_dir): - with override_settings(NPM_STATIC_FILES_PREFIX='lib', NPM_FILE_PATTERNS={'mocha': ['*/*js']}): + with override_settings(NPM_STATIC_FILES_PREFIX='lib', NPM_FILE_PATTERNS={'mocha': ['*{0.sep}*js'.format(os)]}): f = NpmFinder() - assert f.find('lib/mocha/lib/test.js') + assert f.find(normpath('lib/mocha/lib/test.js')) def test_no_matching_paths_returns_empty_list(npm_dir): with override_settings(NPM_FILE_PATTERNS={'foo': ['bar']}): f = NpmFinder() - assert f.find('mocha/mocha.js') == [] + assert f.find(normpath('mocha/mocha.js')) == [] def test_finder_cache(npm_dir): From 70b346b21645ba8848e6af1ab569b43f593585d6 Mon Sep 17 00:00:00 2001 From: alexsilva Date: Tue, 16 Jul 2019 16:31:16 -0300 Subject: [PATCH 24/27] Fix windows erro when location does not exists. --- npm/finders.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/npm/finders.py b/npm/finders.py index 2610968..1ba3c3c 100644 --- a/npm/finders.py +++ b/npm/finders.py @@ -137,6 +137,8 @@ def list(self, ignore_patterns=None): # TODO should be configurable, add settin def _make_list_generator(self, ignore_patterns=None): for prefix, root in self.locations: + if not os.path.exists(root): + continue storage = self.storages[root] for path in get_files(storage, self.match_patterns, ignore_patterns): yield path, storage From 8d5c55c0219fda074ceabdd93b3806e65a008d9e Mon Sep 17 00:00:00 2001 From: alexsilva Date: Wed, 11 Sep 2019 18:01:43 -0300 Subject: [PATCH 25/27] Fix flatten_patterns path. --- npm/finders.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm/finders.py b/npm/finders.py index 1ba3c3c..be95319 100644 --- a/npm/finders.py +++ b/npm/finders.py @@ -60,7 +60,7 @@ def flatten_patterns(patterns): if patterns is None: return None return [ - os.path.join(module, module_pattern) + os.path.normpath(os.path.join(module, module_pattern)) for module, module_patterns in patterns.items() for module_pattern in module_patterns ] From 5991ca493b5f44c6b5cd07aac034a4063cc7815f Mon Sep 17 00:00:00 2001 From: alexsilva Date: Fri, 6 Jan 2023 17:30:29 -0300 Subject: [PATCH 26/27] Add classifier python 3.9 --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 8dd614a..57a0a41 100644 --- a/setup.py +++ b/setup.py @@ -30,6 +30,7 @@ 'Programming Language :: Python :: 3.2', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.9' ], keywords='django npm staticfiles', From e78c8d1c993bfce0bcb7d819847df54fc0872891 Mon Sep 17 00:00:00 2001 From: alexsilva Date: Wed, 25 Sep 2024 10:02:37 -0300 Subject: [PATCH 27/27] v1.1.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 57a0a41..e570653 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ setup( name='django-npm', - version='1.0.0', + version='1.1.0', description='A django staticfiles finder that uses npm', url='https://github.com/kevin1024/django-npm', author='Kevin McCarthy',