| OLD | NEW |
| 1 # Copyright (c) 2014 The Native Client Authors. All rights reserved. | 1 # Copyright (c) 2014 The Native Client Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import os | 5 import os |
| 6 import posixpath | 6 import posixpath |
| 7 import shutil | 7 import shutil |
| 8 import stat |
| 8 import tarfile | 9 import tarfile |
| 9 | 10 |
| 10 from naclports import configuration, package, util, error | 11 from naclports import configuration, package, util, error |
| 11 | 12 |
| 12 PAYLOAD_DIR = 'payload' | 13 PAYLOAD_DIR = 'payload' |
| 13 | 14 |
| 14 ELF_MAGIC = '\x7fELF' | 15 ELF_MAGIC = '\x7fELF' |
| 15 | 16 |
| 16 def IsElfFile(filename): | 17 def IsElfFile(filename): |
| 17 if os.path.islink(filename): | 18 if os.path.islink(filename): |
| 18 return False | 19 return False |
| 19 with open(filename) as f: | 20 with open(filename) as f: |
| 20 header = f.read(4) | 21 header = f.read(4) |
| 21 return header == ELF_MAGIC | 22 return header == ELF_MAGIC |
| 22 | 23 |
| 23 | 24 |
| 24 def FilterOutExecutables(filenames, root): | |
| 25 rtn = [] | |
| 26 for name in filenames: | |
| 27 full_name = os.path.join(root, name) | |
| 28 if os.path.split(name)[0] == 'bin' and IsElfFile(full_name): | |
| 29 continue | |
| 30 rtn.append(name) | |
| 31 | |
| 32 return rtn | |
| 33 | |
| 34 | |
| 35 def InstallFile(filename, old_root, new_root): | 25 def InstallFile(filename, old_root, new_root): |
| 36 """Install a single file by moving it into a new location. | 26 """Install a single file by moving it into a new location. |
| 37 | 27 |
| 38 Args: | 28 Args: |
| 39 filename: Relative name of file to install. | 29 filename: Relative name of file to install. |
| 40 old_root: The current location of the file. | 30 old_root: The current location of the file. |
| 41 new_root: The new desired root for the file. | 31 new_root: The new desired root for the file. |
| 42 """ | 32 """ |
| 43 oldname = os.path.join(old_root, filename) | 33 oldname = os.path.join(old_root, filename) |
| 44 | 34 |
| 45 util.LogVerbose('install: %s' % filename) | 35 util.LogVerbose('install: %s' % filename) |
| 46 | 36 |
| 47 newname = os.path.join(new_root, filename) | 37 newname = os.path.join(new_root, filename) |
| 48 dirname = os.path.dirname(newname) | 38 dirname = os.path.dirname(newname) |
| 49 if not os.path.isdir(dirname): | 39 if not os.path.isdir(dirname): |
| 50 util.Makedirs(dirname) | 40 util.Makedirs(dirname) |
| 51 os.rename(oldname, newname) | 41 os.rename(oldname, newname) |
| 52 | 42 |
| 43 # When install binarie ELF files into the toolchain direcoties, remove |
| 44 # the X bit so that they do not found when searching the PATH. |
| 45 if IsElfFile(newname): |
| 46 mode = os.stat(newname).st_mode |
| 47 mode = mode & ~(stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) |
| 48 os.chmod(newname, mode) |
| 49 |
| 50 |
| 53 | 51 |
| 54 def RelocateFile(filename, dest): | 52 def RelocateFile(filename, dest): |
| 55 """Perform in-place mutations on file contents to handle new location. | 53 """Perform in-place mutations on file contents to handle new location. |
| 56 | 54 |
| 57 There are a few file types that have absolute pathnames embedded | 55 There are a few file types that have absolute pathnames embedded |
| 58 and need to be modified in some way when being installed to | 56 and need to be modified in some way when being installed to |
| 59 a particular location. For most file types this method does nothing. | 57 a particular location. For most file types this method does nothing. |
| 60 """ | 58 """ |
| 61 # Only relocate certain file types. | 59 # Only relocate certain file types. |
| 62 modify = False | 60 modify = False |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 137 Currently only packages built with the same SDK major version | 135 Currently only packages built with the same SDK major version |
| 138 are installable. | 136 are installable. |
| 139 """ | 137 """ |
| 140 return self.BUILD_SDK_VERSION == util.GetSDKVersion() | 138 return self.BUILD_SDK_VERSION == util.GetSDKVersion() |
| 141 | 139 |
| 142 def GetPkgInfo(self): | 140 def GetPkgInfo(self): |
| 143 """Extract the contents of the pkg_info file from the binary package.""" | 141 """Extract the contents of the pkg_info file from the binary package.""" |
| 144 with tarfile.open(self.filename) as tar: | 142 with tarfile.open(self.filename) as tar: |
| 145 return tar.extractfile('./pkg_info').read() | 143 return tar.extractfile('./pkg_info').read() |
| 146 | 144 |
| 147 def Install(self): | 145 def Install(self, force): |
| 148 """Install binary package into toolchain directory.""" | 146 """Install binary package into toolchain directory.""" |
| 149 with util.InstallLock(self.config): | 147 with util.InstallLock(self.config): |
| 150 self._Install() | 148 self._Install(force) |
| 151 | 149 |
| 152 def _Install(self): | 150 def _Install(self, force): |
| 153 dest = util.GetInstallRoot(self.config) | 151 dest = util.GetInstallRoot(self.config) |
| 154 dest_tmp = os.path.join(dest, 'install_tmp') | 152 dest_tmp = os.path.join(dest, 'install_tmp') |
| 155 if os.path.exists(dest_tmp): | 153 if os.path.exists(dest_tmp): |
| 156 shutil.rmtree(dest_tmp) | 154 shutil.rmtree(dest_tmp) |
| 157 | 155 |
| 158 if self.IsAnyVersionInstalled(): | 156 if self.IsAnyVersionInstalled(): |
| 159 raise error.Error('package already installed: %s' % self.InfoString()) | 157 raise error.Error('package already installed: %s' % self.InfoString()) |
| 160 | 158 |
| 161 self.LogStatus('Installing') | 159 self.LogStatus('Installing') |
| 162 util.LogVerbose('installing from: %s' % self.filename) | 160 util.LogVerbose('installing from: %s' % self.filename) |
| 163 util.Makedirs(dest_tmp) | 161 util.Makedirs(dest_tmp) |
| 164 | 162 |
| 165 names = [] | 163 names = [] |
| 166 try: | 164 try: |
| 167 with tarfile.open(self.filename) as tar: | 165 with tarfile.open(self.filename) as tar: |
| 168 for info in tar: | 166 for info in tar: |
| 169 if info.isdir(): | 167 if info.isdir(): |
| 170 continue | 168 continue |
| 171 name = posixpath.normpath(info.name) | 169 name = posixpath.normpath(info.name) |
| 172 if name == 'pkg_info': | 170 if name == 'pkg_info': |
| 173 continue | 171 continue |
| 174 if not name.startswith(PAYLOAD_DIR + '/'): | 172 if not name.startswith(PAYLOAD_DIR + '/'): |
| 175 raise error.PkgFormatError('invalid file in package: %s' % name) | 173 raise error.PkgFormatError('invalid file in package: %s' % name) |
| 176 | 174 |
| 177 name = name[len(PAYLOAD_DIR) + 1:] | 175 name = name[len(PAYLOAD_DIR) + 1:] |
| 178 names.append(name) | 176 names.append(name) |
| 179 | 177 |
| 180 for name in names: | 178 if not force: |
| 181 full_name = os.path.join(dest, name) | 179 for name in names: |
| 182 if os.path.exists(full_name): | 180 full_name = os.path.join(dest, name) |
| 183 raise error.Error('file already exists: %s' % full_name) | 181 if os.path.exists(full_name) : |
| 182 raise error.Error('file already exists: %s' % full_name) |
| 184 | 183 |
| 185 tar.extractall(dest_tmp) | 184 tar.extractall(dest_tmp) |
| 186 payload_tree = os.path.join(dest_tmp, PAYLOAD_DIR) | 185 payload_tree = os.path.join(dest_tmp, PAYLOAD_DIR) |
| 187 | 186 |
| 188 # Filter out ELF binaries in the bin directory. We don't want NaCl | |
| 189 # exectuables installed in the toolchain's bin directory since we | |
| 190 # add this to the PATH during the build process, and NaCl executables | |
| 191 # can't be run on the host system (not without sel_ldr anyway). | |
| 192 names = FilterOutExecutables(names, payload_tree) | |
| 193 for name in names: | 187 for name in names: |
| 194 InstallFile(name, payload_tree, dest) | 188 InstallFile(name, payload_tree, dest) |
| 195 finally: | 189 finally: |
| 196 shutil.rmtree(dest_tmp) | 190 shutil.rmtree(dest_tmp) |
| 197 | 191 |
| 198 for name in names: | 192 for name in names: |
| 199 RelocateFile(name, dest) | 193 RelocateFile(name, dest) |
| 200 | 194 |
| 201 self.WriteFileList(names) | 195 self.WriteFileList(names) |
| 202 self.WriteStamp() | 196 self.WriteStamp() |
| 203 | 197 |
| 204 def WriteStamp(self): | 198 def WriteStamp(self): |
| 205 """Write stamp file containing pkg_info.""" | 199 """Write stamp file containing pkg_info.""" |
| 206 filename = util.GetInstallStamp(self.NAME, self.config) | 200 filename = util.GetInstallStamp(self.NAME, self.config) |
| 207 util.LogVerbose('stamp: %s' % filename) | 201 util.LogVerbose('stamp: %s' % filename) |
| 208 pkg_info = self.GetPkgInfo() | 202 pkg_info = self.GetPkgInfo() |
| 209 with open(filename, 'w') as f: | 203 with open(filename, 'w') as f: |
| 210 f.write(pkg_info) | 204 f.write(pkg_info) |
| 211 | 205 |
| 212 def WriteFileList(self, file_names): | 206 def WriteFileList(self, file_names): |
| 213 """Write the file list for this package.""" | 207 """Write the file list for this package.""" |
| 214 filename = self.GetListFile() | 208 filename = self.GetListFile() |
| 215 dirname = os.path.dirname(filename) | 209 dirname = os.path.dirname(filename) |
| 216 if not os.path.isdir(dirname): | 210 if not os.path.isdir(dirname): |
| 217 util.Makedirs(dirname) | 211 util.Makedirs(dirname) |
| 218 with open(filename, 'w') as f: | 212 with open(filename, 'w') as f: |
| 219 for name in file_names: | 213 for name in file_names: |
| 220 f.write(name + '\n') | 214 f.write(name + '\n') |
| OLD | NEW |