1import os
2import sys
3
4sys.path.insert(1, os.path.dirname(sys.path[0]))  # noqa - don't warn about imports
5
6from mozharness.base.log import FATAL
7from mozharness.base.script import BaseScript
8
9
10class Repackage(BaseScript):
11
12    def __init__(self, require_config_file=False):
13        script_kwargs = {
14            'all_actions': [
15                "setup",
16                "repackage",
17            ],
18        }
19        BaseScript.__init__(
20            self,
21            require_config_file=require_config_file,
22            **script_kwargs
23        )
24
25    def setup(self):
26        dirs = self.query_abs_dirs()
27
28        self._run_tooltool()
29
30        mar_path = os.path.join(dirs['abs_input_dir'], 'mar')
31        if self._is_windows():
32            mar_path += '.exe'
33        if mar_path and os.path.exists(mar_path):
34            self.chmod(mar_path, 0o755)
35        if self.config.get("run_configure", True):
36            self._get_mozconfig()
37            self._run_configure()
38
39    def query_abs_dirs(self):
40        if self.abs_dirs:
41            return self.abs_dirs
42        abs_dirs = super(Repackage, self).query_abs_dirs()
43        config = self.config
44
45        dirs = {}
46        dirs['abs_input_dir'] = os.path.join(abs_dirs['base_work_dir'], 'fetches')
47        output_dir_suffix = []
48        if config.get('locale'):
49            output_dir_suffix.append(config['locale'])
50        if config.get('repack_id'):
51            output_dir_suffix.append(config['repack_id'])
52        dirs['abs_output_dir'] = os.path.join(
53            abs_dirs['abs_work_dir'], 'outputs', *output_dir_suffix)
54        for key in dirs.keys():
55            if key not in abs_dirs:
56                abs_dirs[key] = dirs[key]
57        self.abs_dirs = abs_dirs
58        return self.abs_dirs
59
60    def repackage(self):
61        config = self.config
62        dirs = self.query_abs_dirs()
63
64        subst = {
65            'package-name': config['package-name'],
66            # sfx-stub is only defined for Windows targets
67            'sfx-stub': config.get('sfx-stub'),
68            'installer-tag': config['installer-tag'],
69            'stub-installer-tag': config['stub-installer-tag'],
70            'wsx-stub': config['wsx-stub'],
71        }
72        subst.update(dirs)
73        if config.get('fetch-dir'):
74            subst.update({'fetch-dir': os.path.abspath(config['fetch-dir'])})
75
76        # Make sure the upload dir is around.
77        self.mkdir_p(dirs['abs_output_dir'])
78
79        for repack_config in config["repackage_config"]:
80            command = [sys.executable, 'mach', '--log-no-times', 'repackage']
81            command.extend([arg.format(**subst) for arg in repack_config['args']])
82            for arg, filename in repack_config['inputs'].items():
83                command.extend([
84                    '--{}'.format(arg),
85                    os.path.join(dirs['abs_input_dir'], filename),
86                ])
87            command.extend([
88                '--output', os.path.join(dirs['abs_output_dir'], repack_config['output']),
89            ])
90            self.run_command(
91                command=command,
92                cwd=dirs['abs_src_dir'],
93                halt_on_failure=True,
94                env=self.query_env(),
95            )
96
97    def _run_tooltool(self):
98        config = self.config
99        dirs = self.query_abs_dirs()
100        toolchains = os.environ.get('MOZ_TOOLCHAINS')
101        manifest_src = os.environ.get('TOOLTOOL_MANIFEST')
102        if not manifest_src:
103            manifest_src = config.get('tooltool_manifest_src')
104        if not manifest_src and not toolchains:
105            return
106
107        cmd = [
108            sys.executable, '-u',
109            os.path.join(dirs['abs_src_dir'], 'mach'),
110            'artifact',
111            'toolchain',
112            '-v',
113            '--retry', '4',
114            '--artifact-manifest',
115            os.path.join(dirs['abs_src_dir'], 'toolchains.json'),
116        ]
117        if manifest_src:
118            cmd.extend([
119                '--tooltool-manifest',
120                os.path.join(dirs['abs_src_dir'], manifest_src),
121            ])
122            auth_file = self._get_tooltool_auth_file()
123            if auth_file:
124                cmd.extend(['--authentication-file', auth_file])
125        cache = config.get('tooltool_cache')
126        if cache:
127            cmd.extend(['--cache-dir', cache])
128        if toolchains:
129            cmd.extend(toolchains.split())
130        self.info(str(cmd))
131        self.run_command(cmd, cwd=dirs['abs_src_dir'], halt_on_failure=True)
132
133    def _get_tooltool_auth_file(self):
134        # set the default authentication file based on platform; this
135        # corresponds to where puppet puts the token
136        if 'tooltool_authentication_file' in self.config:
137            fn = self.config['tooltool_authentication_file']
138        elif self._is_windows():
139            fn = r'c:\builds\relengapi.tok'
140        else:
141            fn = '/builds/relengapi.tok'
142
143        # if the file doesn't exist, don't pass it to tooltool (it will just
144        # fail).  In taskcluster, this will work OK as the relengapi-proxy will
145        # take care of auth.  Everywhere else, we'll get auth failures if
146        # necessary.
147        if os.path.exists(fn):
148            return fn
149
150    def _get_mozconfig(self):
151        """assign mozconfig."""
152        c = self.config
153        dirs = self.query_abs_dirs()
154        abs_mozconfig_path = ''
155
156        # first determine the mozconfig path
157        if c.get('src_mozconfig'):
158            self.info('Using in-tree mozconfig')
159            abs_mozconfig_path = os.path.join(dirs['abs_src_dir'], c['src_mozconfig'])
160        else:
161            self.fatal("'src_mozconfig' must be in the config "
162                       "in order to determine the mozconfig.")
163
164        # print its contents
165        self.read_from_file(abs_mozconfig_path, error_level=FATAL)
166
167        # finally, copy the mozconfig to a path that 'mach build' expects it to be
168        self.copyfile(abs_mozconfig_path, os.path.join(dirs['abs_src_dir'], '.mozconfig'))
169
170    def _run_configure(self):
171        dirs = self.query_abs_dirs()
172        command = [sys.executable, 'mach', '--log-no-times', 'configure']
173        return self.run_command(
174            command=command,
175            cwd=dirs['abs_src_dir'],
176            output_timeout=60*3,
177            halt_on_failure=True,
178        )
179
180
181if __name__ == '__main__':
182    repack = Repackage()
183    repack.run_and_exit()
184