aboutsummaryrefslogtreecommitdiffstats
path: root/build/plugins/lib/nots/package_manager/base/package_manager.py
blob: 0de9d8acc33a729f59d56882c2b204a8a7aa4380 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import os
import sys
import subprocess
import tarfile

from abc import ABCMeta, abstractmethod
from six import add_metaclass

from . import constants


class PackageManagerError(RuntimeError):
    pass


class PackageManagerCommandError(PackageManagerError):
    def __init__(self, cmd, code, stdout, stderr):
        self.cmd = cmd
        self.code = code
        self.stdout = stdout
        self.stderr = stderr

        msg = "package manager exited with code {} while running {}:\n{}\n{}".format(code, cmd, stdout, stderr)
        super(PackageManagerCommandError, self).__init__(msg)


@add_metaclass(ABCMeta)
class BasePackageManager(object):
    def __init__(self, build_root, build_path, sources_path, nodejs_bin_path, script_path, contribs_path):
        self.module_path = build_path[len(build_root) + 1:]
        self.build_path = build_path
        self.sources_path = sources_path
        self.build_root = build_root
        self.sources_root = sources_path[:-len(self.module_path) - 1]
        self.nodejs_bin_path = nodejs_bin_path
        self.script_path = script_path
        self.contribs_path = contribs_path

    @abstractmethod
    def install(self):
        pass

    @abstractmethod
    def get_peer_paths_from_package_json(self):
        pass

    @abstractmethod
    def calc_node_modules_inouts(self):
        pass

    @abstractmethod
    def extract_packages_meta_from_lockfiles(self, lf_paths):
        pass

    def create_node_modules_bundle(self, path):
        """
        Creates tarball from the node_modules directory contents.
        :param path: tarball path
        :type path: str
        """
        with tarfile.open(path, "w") as tf:
            tf.add(self._nm_path(), arcname=".")

    def _exec_command(self, args, include_defaults=True):
        if not self.nodejs_bin_path:
            raise PackageManagerError("Unable to execute command: nodejs_bin_path is not configured")

        cmd = [self.nodejs_bin_path, self.script_path] + args + (self._get_default_options() if include_defaults else [])
        p = subprocess.Popen(
            cmd,
            cwd=self.build_path,
            stdin=None,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
        )
        stdout, stderr = p.communicate()

        if p.returncode != 0:
            self._dump_debug_log()

            raise PackageManagerCommandError(cmd, p.returncode, stdout.decode("utf-8"), stderr.decode("utf-8"))

    def _nm_path(self, *parts):
        return os.path.join(self.build_path, "node_modules", *parts)

    def _contrib_tarball_path(self, pkg):
        return os.path.join(self.contribs_path, pkg.tarball_path)

    def _contrib_tarball_url(self, pkg):
        return "file:" + self._contrib_tarball_path(pkg)

    def _get_default_options(self):
        return ["--registry", constants.NPM_REGISTRY_URL]

    def _get_debug_log_path(self):
        return None

    def _dump_debug_log(self):
        log_path = self._get_debug_log_path()

        if not log_path:
            return

        try:
            with open(log_path) as f:
                sys.stderr.write("Package manager log {}:\n{}\n".format(log_path, f.read()))
        except:
            sys.stderr.write("Failed to dump package manager log {}.\n".format(log_path))