def _dodoc(*source_files, **kw): """copy doc files to /usr/share/doc/src_name recursively""" dest = util.join_path(get.docDIR(), kw.get('dest_dir', get.srcNAME())) destination = util.join_path(get.installDIR(), dest) if not os.access(destination, os.F_OK): os.makedirs(destination) for source_file in source_files: sources = glob(source_file) if not sources: raise DoJavadocError( _('No any file/directory matched to regex expression "{}".'. format(source_file))) for source in sources: if os.path.isfile(source): try: copy(source, destination) except IOError: raise DoJavadocError(_('DoJavadoc failed.')) elif os.path.isdir(source): target = util.join_path(destination, source.split("/")[-1]) try: copytree(source, target) except IOError: raise DoJavadocError(_('DoJavadoc failed.'))
def create_delta_packages(old_packages, new_package): if new_package in old_packages: ctx.ui.warning( _("New package \"{}\" exists in the list of old packages. Skipping it..." ).format(new_package)) while new_package in old_packages: old_packages.remove(new_package) new_pkg_name = os.path.splitext(os.path.basename(new_package))[0] new_pkg_path = util.join_path(ctx.config.tmp_dir(), new_pkg_name) new_pkg = inary.package.Package(new_package, tmp_dir=new_pkg_path) new_pkg.read() # Unpack new package to temp new_pkg.extract_inary_files(new_pkg_path) new_pkg.extract_dir("scom", new_pkg_path) install_dir = util.join_path(new_pkg_path, "install") util.clean_dir(install_dir) os.mkdir(install_dir) new_pkg.extract_install(install_dir) delta_packages = create_delta_packages_from_obj(old_packages, new_pkg, new_pkg_path) # Remove temp dir util.clean_dir(new_pkg_path) # Return delta package names return delta_packages
def add_repo(self, name, repo_info, at=None): repo_path = util.join_path(ctx.config.index_dir(), name) ########### try: os.makedirs(repo_path) except: pass # FIXME: FileExistError errno: 17 # When addind repo there are the same as name empty dirs it should remove it urifile_path = util.join_path(ctx.config.index_dir(), name, "uri") open(urifile_path, "w").write(repo_info.indexuri.get_uri()) self.repoorder.add(name, repo_info.indexuri.get_uri())
def installLib(src='*.jar', dest='/usr/share/java'): """install compilation output that is mix of the utility classes as in jars or meta/data files to specified locations. src: Source file pattern to be installed dest: Destination dir where the source files to be installed """ classpath = [] destination = util.join_path(get.installDIR(), dest) sources = glob(src) # If no source matched, then no need to create destination dir if not sources: raise InstallError( _('No any file/directory matched ' 'to regex expression "{}".'.format(src))) if not os.access(destination, os.F_OK): os.makedirs(destination) for source in sources: if os.path.isfile(source): try: copy(source, destination) except IOError: raise InstallError( _('Installing file "{}" failed.'.format(source))) if source.endswith('.jar'): classpath.append( util.join_path('/', dest, source.split('/')[-1])) elif os.path.isdir(source): target = util.join_path(destination, source.split('/')[-1]) try: copytree(source, target) except IOError: raise InstallError( _('Installing directory "{}" failed.'.format(source))) for root, dirs, files in os.walk(target): for f in files: if f.endswith('.jar'): # Exclude sandbox dir from jar path jar = util.remove_prefix(get.installDIR(), util.join_path(root, f)) classpath.append(jar) if classpath: _generate_classpath_file(classpath)
def _generate_exec_file(dest_dir, exe, java_args, exe_args): """generate executable file for executable jar""" exec_dir = util.join_path(get.installDIR(), '/usr/bin') if not os.access(exec_dir, os.F_OK): os.makedirs(exec_dir) # Using low level I/O to set permission without calling os.chmod exec_file = os.open(util.join_path(exec_dir, get.srcNAME()), os.O_CREAT | os.O_WRONLY, 0o755) os.write( exec_file, EXEC_TEMPLATE.format(util.join_path('/', dest_dir), java_args, exe, exe_args)) os.close(exec_file)
def show_changed_configs(package_dict, opt): for package in package_dict: if package_dict[package]: if ctx.ui.confirm(util.colorize( _("[?] Would you like to see changes in config files of \"{0}\" package").format( package), color='brightyellow')): for file in package_dict[package]: new_file = util.join_path( ctx.config.history_dir(), opt, package, ctx.config.dest_dir(), file) if os.path.exists(new_file): if ctx.config.options and ctx.config.options.yes_all: prompt = "1" else: ctx.ui.info( _("[*] Changes in config file: {}").format(file), color='yellow') os.system( "diff -u {0} {1} | less".format(new_file, file)) ctx.ui.info(_("[?] Select the process which will be happened:")) ctx.ui.info(_("1. Store new config file, not apply [*]")) ctx.ui.info(_("2. Apply new config file (keep old config)")) ctx.ui.info(_("3. Apply new config file (don't keep old config)")) ctx.ui.info(_("4. Delete new config file")) prompt = subprocess.getoutput("read -n 1 c ; echo $c") if prompt == "1": pass elif pprompt == "2": apply_changed_config( util.join_path( ctx.config.dest_dir(), file), new_file, keep=True) elif pprompt == "3": apply_changed_config( util.join_path( ctx.config.dest_dir(), file), new_file, keep=False) else: ctx.ui.info( _("Deleting new config file {0}").format(file), verbose=True) util.delete_file(new_file)
def installExe(exe='', java_args='', exe_args='', dest_dir=''): """install executable jar to specified location and get jar prepared to execute with given arguments. exe: Path in work dir to executable jar java_args: Arguments passed to jvm exe_args: Arguments passed to executable jar dest_dir: Installation dir of executable jar""" if not dest_dir: dest_dir = 'usr/share/java/{}'.format(get.srcNAME()) destination = util.join_path(get.installDIR(), dest_dir) if not os.access(destination, os.F_OK): os.makedirs(destination) # To guarantee x/y.jar going under /usr/share/java as y.jar source = exe.split("/")[-1] try: copy(exe, destination) _generate_exec_file(dest_dir, source, ' {} '.format(java_args) if java_args else ' ', ' {}'.format(exe_args) if exe_args else '') except IOError: raise InstallError(_('Installing file "{}" failed.'.format(exe)))
def _generate_classpath_file(classpath): """write classpath to environment file""" env_dir = util.join_path(get.installDIR(), '/etc/env.d') if not os.access(env_dir, os.F_OK): os.makedirs(env_dir) env_file = util.join_path(env_dir, get.srcNAME()) if not os.access(env_file, os.F_OK): prefix = 'CLASSPATH=' else: prefix = ':' cp_file = open(env_file, 'a') cp_file.write('{0}{1}'.format(prefix, ':'.join(classpath))) cp_file.close()
def configure(parameters='', installPrefix='/{}'.format(get.defaultprefixDIR()), sourceDir='.'): """configure source with given cmake parameters = "-DCMAKE_BUILD_TYPE -DCMAKE_CXX_FLAGS ... " """ if can_access_file(join_path(sourceDir, 'CMakeLists.txt')): args = 'cmake -DCMAKE_INSTALL_PREFIX={0} \ -DCMAKE_INSTALL_LIBDIR={1} \ -DCMAKE_BUILD_TYPE=RelWithDebInfo {2} {3}'.format( installPrefix, "/usr/lib32 " if get.buildTYPE() == "emul32" else "/usr/lib", parameters, sourceDir) if get.CFLAGS(): args += ' -DCMAKE_C_FLAGS="{0} {1}"'.format( get.CFLAGS(), "-m32" if get.buildTYPE() == "emul32" else "-m64") if get.CXXFLAGS(): args += ' -DCMAKE_CXX_FLAGS="{0} {1}"'.format( get.CXXFLAGS(), "-m32" if get.buildTYPE() == "emul32" else "-m64") if get.LDFLAGS(): args += ' -DCMAKE_LD_FLAGS="{0}"'.format(get.LDFLAGS()) if system(args): raise ConfigureError(_('Configure failed.')) else: raise ConfigureError( _('No configure script found. (\"{}\" file not found.)'.format( "CMakeLists.txt")))
def get_repo_doc(self, repo_name): repo = self.get_repo(repo_name) index_path = repo.indexuri.get_uri() # FIXME Local index files should also be cached. if File.is_compressed(index_path) or repo.indexuri.is_remote_file(): index = os.path.basename(index_path) index_path = util.join_path(ctx.config.index_dir(), repo_name, index) if File.is_compressed(index_path): index_path = os.path.splitext(index_path)[0] if not os.path.exists(index_path): ctx.ui.warning( _("{} repository needs to be updated").format(repo_name)) return xmlext.newDocument("INARY") try: return xmlext.parse(index_path) except Exception as e: raise RepoError( _("Error parsing repository index information: {} \n Index file does not exist or is malformed." ).format(e))
def remove_file(fileinfo, package_name, remove_permanent=False, store_old_paths=None): if fileinfo.permanent and not remove_permanent: return fpath = util.join_path(ctx.config.dest_dir(), fileinfo.path) historydb = inary.db.historydb.HistoryDB() # we should check if the file belongs to another # package (this can legitimately occur while upgrading # two packages such that a file has moved from one package to # another as in #2911) pkg = ctx.filesdb.get_filename(fileinfo.path) if pkg and pkg != package_name: ctx.ui.warning( _('Not removing conflicted file : \"{}\"').format(fpath)) return if fileinfo.type == ctx.const.conf: # config files are precious, leave them as they are # unless they are the same as provided by package. # remove symlinks as they are, cause if the hash of the # file it links has changed, it will be kept as is, # and when the package is reinstalled the symlink will # link to that changed file again. try: if os.path.islink(fpath) or util.sha1_file( fpath) == fileinfo.hash: os.unlink(fpath) else: # keep changed file in history historydb.save_config(package_name, fpath) # after saving to history db, remove the config file any # way if ctx.config.get_option("purge"): os.unlink(fpath) except FileError: pass else: if os.path.isfile(fpath) or os.path.islink(fpath): os.unlink(fpath) if store_old_paths: open(store_old_paths, "a").write("{}\n".format(fpath)) elif os.path.isdir(fpath) and not os.listdir(fpath): os.rmdir(fpath) else: ctx.ui.warning( _('Installed file \"{}\" does not exist on system [Probably you manually deleted]' ).format(fpath)) return # remove emptied directories dpath = os.path.dirname(fpath) while dpath != '/' and os.path.exists(dpath) and not os.listdir(dpath): os.rmdir(dpath) dpath = os.path.dirname(dpath)
def postinstall(self): # Chowning for additional files for _file in self.package.get_files().list: fpath = util.join_path(ctx.config.dest_dir(), _file.path) if os.path.islink(fpath): if os.path.lexists(fpath) and os.path.exists(fpath): ctx.ui.info(_("Added symlink '{}' ").format(fpath), verbose=True) else: ctx.ui.warning( _("Broken or missing symlink '{}'").format(fpath)) if 'postOps' in self.metadata.package.isA: if ctx.config.get_option( 'ignore_configure') or ctx.config.get_option('destdir'): self.installdb.mark_pending(self.pkginfo.name) return 0 ctx.ui.info(_('Configuring post-install \"{}\"'.format( self.pkginfo.name)), color='brightyellow') if not self.trigger.postinstall(self.package.pkg_dir()): ctx.ui.error( _('Post-install configuration of \"{}\" package failed.'). format(self.pkginfo.name)) self.installdb.mark_pending(self.pkginfo.name) return 0
def snapshot(): """ Takes snapshot of the system packages. The snapshot is only a record of which packages are currently installed. The record is kept by inary history mechanism as it works automatically on install, remove and upgrade operations. """ installdb = inary.db.installdb.InstallDB() historydb = inary.db.historydb.HistoryDB() historydb.create_history("snapshot") li = installdb.list_installed() progress = ctx.ui.Progress(len(li)) processed = 0 for name in installdb.list_installed(): package = installdb.get_package(name) historydb.add_package(pkgBefore=package, operation="snapshot") # Save changed config files of the package in snapshot for f in installdb.get_files(name).list: if f.type == "config" and util.config_changed(f): fpath = util.join_path(ctx.config.dest_dir(), f.path) historydb.save_config(name, fpath) processed += 1 ctx.ui.display_progress(operation="snapshot", percent=progress.update(processed), info=_("Taking snapshot of the system.")) ctx.ui.info("") historydb.update_history()
def preinstall(self, specdir): self.specdir = specdir for postops in ctx.const.postops: self.postscript = util.join_path(self.specdir, postops) retval = self.run_command("preInstall") util.delete_file(self.postscript) return retval
def copy(source, destination, sym=True): """recursively copy a "source" file or directory to "destination\" """ sourceGlob = glob.glob(source) if len(sourceGlob) == 0: error( _("ActionsAPI [copy]: No file matched pattern \"{}\".").format( source)) for filePath in sourceGlob: if isFile(filePath) and not isLink(filePath): try: shutil.copy(filePath, destination) except IOError: error( _('ActionsAPI [copy]: Permission denied: \"{0}\" to \"{1}\"' ).format(filePath, destination)) elif isLink(filePath) and sym: if isDirectory(destination): os.symlink(os.readlink(filePath), join_path(destination, os.path.basename(filePath))) else: if isFile(destination): os.remove(destination) os.symlink(os.readlink(filePath), destination) elif isLink(filePath) and not sym: if isDirectory(filePath): copytree(filePath, destination) else: shutil.copy(filePath, destination) elif isDirectory(filePath): copytree(filePath, destination, sym) else: error( _('ActionsAPI [copy]: File \"{}\" does not exist.').format( filePath))
def extract_file_synced(self, path, outdir): """Extract file with path to outdir""" data = self.impl.read_file(path) fpath = util.join_path(outdir, path) util.ensure_dirs(os.path.dirname(fpath)) with open(fpath, "wb") as f: f.write(data.encode("utf-8")) f.flush() os.fsync(f.fileno())
def subdir(self, path): subdir = util.join_path(self.dest_dir(), path) # If the directory does not exist, try to create it. try: util.ensure_dirs(subdir) except OSError: pass return subdir
def add_to_install(self, name, arcname=None): """Add the file 'name' to the install archive""" if arcname is None: arcname = name if self.format == "1.0": arcname = util.join_path("install", arcname) self.add_to_package(name, arcname) return if self.install_archive is None: archive_name, archive_format = \ self.archive_name_and_format(self.format) self.install_archive_path = util.join_path(self.tmp_dir, archive_name) ctx.build_leftover = self.install_archive_path self.install_archive = archive.ArchiveTar( self.install_archive_path, archive_format) self.install_archive.add_to_archive(name, arcname)
def unpack_dir(self, target_dir): """Unpack LZMA archive to a given target directory(target_dir).""" output_path = util.join_path(target_dir, os.path.basename(self.file_path)) ext = ".lzma" if self.type == "lzma" else ".xz" if output_path.endswith(ext): output_path = output_path[:-len(ext)] lzma_file = lzma.LZMAFile(self.file_path) output = open(output_path, "w") output.write(lzma_file.read().decode("utf-8")) output.close() lzma_file.close()
def unpack_dir(self, target_dir): """Unpack Gzip archive to a given target directory(target_dir).""" output_path = util.join_path(target_dir, os.path.basename(self.file_path)) if output_path.endswith(".gz"): output_path = output_path[:-3] import gzip gzip_file = gzip.GzipFile(self.file_path, "r") output = open(output_path, "w") output.write(gzip_file.read().decode("utf-8")) output.close() gzip_file.close()
def unpack_dir(self, target_dir): """Unpack Bzip2 archive to a given target directory(target_dir).""" output_path = util.join_path(target_dir, os.path.basename(self.file_path)) if output_path.endswith(".bz2"): output_path = output_path[:-4] import bz2 bz2_file = bz2.BZ2File(self.file_path) output = open(output_path, "w") output.write(bz2_file.read().decode("utf-8")) output.close() bz2_file.close()
def configure_pending(packages=None): # Import SCOM import inary.scomiface # start with pending packages # configure them in reverse topological order of dependency installdb = inary.db.installdb.InstallDB() if not packages: packages = installdb.list_pending() else: packages = set(packages).intersection(installdb.list_pending()) order = inary.data.pgraph.generate_pending_order(packages) try: for x in order: if installdb.has_package(x): pkginfo = installdb.get_package(x) pkg_path = installdb.package_path(x) m = inary.data.metadata.MetaData() metadata_path = util.join_path(pkg_path, ctx.const.metadata_xml) m.read(metadata_path) # FIXME: we need a full package info here! pkginfo.name = x ctx.ui.notify(inary.ui.configuring, package=pkginfo, files=None) inary.scomiface.post_install( pkginfo.name, m.package.providesScom, util.join_path(pkg_path, ctx.const.scom_dir), util.join_path(pkg_path, ctx.const.metadata_xml), util.join_path(pkg_path, ctx.const.files_xml), None, None, m.package.version, m.package.release) ctx.ui.notify(inary.ui.configured, package=pkginfo, files=None) installdb.clear_pending(x) except ImportError: raise inary.errors.Error(_("scom package is not fully installed."))
def calculate_download_sizes(order): total_size = cached_size = 0 installdb = inary.db.installdb.InstallDB() packagedb = inary.db.packagedb.PackageDB() try: cached_packages_dir = ctx.config.cached_packages_dir() except OSError: # happens when cached_packages_dir tried to be created by an # unpriviledged user cached_packages_dir = None for pkg in [packagedb.get_package(name) for name in order]: delta = None if installdb.has_package(pkg.name): release = installdb.get_release(pkg.name) (distro, distro_release) = installdb.get_distro_release(pkg.name) # inary distro upgrade should not use delta support if distro == pkg.distribution and distro_release == pkg.distributionRelease: delta = pkg.get_delta(release) ignore_delta = ctx.config.values.general.ignore_delta if delta and not ignore_delta: fn = os.path.basename(delta.packageURI) pkg_hash = delta.packageHash pkg_size = delta.packageSize else: fn = os.path.basename(pkg.packageURI) pkg_hash = pkg.packageHash pkg_size = pkg.packageSize if cached_packages_dir: path = util.join_path(cached_packages_dir, fn) # check the file and sha1sum to be sure it _is_ the cached package if os.path.exists(path) and util.sha1_file(path) == pkg_hash: cached_size += pkg_size elif os.path.exists("{}.part".format(path)): cached_size += os.stat("{}.part".format(path)).st_size total_size += pkg_size ctx.ui.notify( ui.cached, logging=False, total=total_size, cached=cached_size) return total_size, cached_size
def ninja_install(parameters=""): insdir = util.join_path( get.installDIR(), "emul32") if get.buildTYPE() == "emul32" else get.installDIR() if system('DESTDIR="{}" ninja install {} -C inaryPackageBuild'.format( insdir, get.makeJOBS())): raise NinjaBuildError(_("Install failed.")) if isDirectory("{}/emul32".format(get.installDIR())): if isDirectory("{}/emul32/lib32".format(get.installDIR())): copy("{}/emul32/lib32".format(get.installDIR()), "{}/".format(get.installDIR())) if isDirectory("{}/emul32/usr/lib32".format(get.installDIR())): copy("{}/emul32/usr/lib32".format(get.installDIR()), "{}/usr/".format(get.installDIR())) removeDir("/emul32")
def copytree(source, destination, sym=True): """recursively copy an entire directory tree rooted at source""" if isDirectory(source): if os.path.exists(destination): if isDirectory(destination): copytree( source, join_path(destination, os.path.basename(source.strip('/')))) return else: copytree(source, join_path(destination, os.path.basename(source))) return try: shutil.copytree(source, destination, sym) except OSError as e: error( _('ActionsAPI [copytree] \"{0}\" to \"{1}\": {2}').format( source, destination, e)) else: error( _('ActionsAPI [copytree]: Directory \"{}\" doesn\'t exists.'). format(source))
def cmake_configure(parameters=""): makedirs("inaryPackageBuild") cd("inaryPackageBuild") if can_access_file(util.join_path("..", 'CMakeLists.txt')): args = 'cmake -DCMAKE_INSTALL_PREFIX=/{0} \ -DCMAKE_INSTALL_LIBDIR={1} \ -DCMAKE_C_FLAGS="{6} {2}" \ -DCMAKE_CXX_FLAGS="{6} {3}" \ -DCMAKE_LD_FLAGS="{4}" \ -DCMAKE_BUILD_TYPE=RelWithDebInfo {5} -G Ninja ..'.format( get.defaultprefixDIR(), "/usr/lib32 " if get.buildTYPE() == "emul32" else "/usr/lib", get.CFLAGS(), get.CXXFLAGS(), get.LDFLAGS(), parameters, "-m32" if get.buildTYPE() == "emul32" else "-m64") if system(args): raise ConfigureError(_('CMake configure failed.')) else: raise ConfigureError( _('No configure script found. (\"{}\" file not found.)'.format( "CMakeLists.txt")))
def read_uri_of_repo(self, uri, repo=None, force=False): """Read PSPEC file""" if repo: tmpdir = os.path.join(ctx.config.index_dir(), repo) else: tmpdir = os.path.join(ctx.config.tmp_dir(), 'index') util.clean_dir(tmpdir) util.ensure_dirs(tmpdir) # write uri urlfile = open(util.join_path(tmpdir, 'uri'), 'w') urlfile.write(uri) # uri urlfile.close() self.read_uri(uri, tmpdir, force) if not repo: repo = self.distribution.name() # and what do we do with it? move it to index dir properly newtmpdir = os.path.join(ctx.config.index_dir(), repo) util.clean_dir(newtmpdir) # replace newtmpdir shutil.move(tmpdir, newtmpdir)
def delete_cache(): """ Deletes cached packages, cached archives, build dirs, db caches """ ctx.ui.info( _("Cleaning package cache \"{}\"...").format( ctx.config.cached_packages_dir())) util.clean_dir(ctx.config.cached_packages_dir()) ctx.ui.info( _("Cleaning source archive cache \"{}\"...").format( ctx.config.archives_dir())) util.clean_dir(ctx.config.archives_dir()) ctx.ui.info( _("Cleaning temporary directory \"{}\"...").format( ctx.config.tmp_dir())) util.clean_dir(ctx.config.tmp_dir()) for cache in [ x for x in os.listdir(ctx.config.cache_root_dir()) if x.endswith(".cache") ]: cache_file = util.join_path(ctx.config.cache_root_dir(), cache) ctx.ui.info(_("Removing cache file \"{}\"...").format(cache_file)) os.unlink(cache_file)
def check_relations(self): # check dependencies # if not ctx.config.get_option('ignore_dependency'): # if not self.pkginfo.installable(): # raise Error(_("{} package cannot be installed unless the dependencies are satisfied").format(self.pkginfo.name)) # If it is explicitly specified that package conflicts with this package and also # we passed check_conflicts tests in operations.py than this means a non-conflicting # pkg is in "order" to be installed that has no file conflict problem with this package. # PS: we need this because "order" generating code does not consider # conflicts. def really_conflicts(pkg): if not self.pkginfo.conflicts: return True return pkg not in [x.package for x in self.pkginfo.conflicts] # check file conflicts file_conflicts = [] for f in self.files.list: pkg, existing_file = ctx.filesdb.get_file(f.path) if pkg: dst = util.join_path(ctx.config.dest_dir(), f.path) if pkg != self.pkginfo.name and not os.path.isdir( dst) and really_conflicts(pkg): file_conflicts.append((pkg, existing_file)) if file_conflicts: file_conflicts_str = "" for (pkg, existing_file) in file_conflicts: file_conflicts_str += _( "\"/{0}\" from \"{1}\" package\n").format( existing_file, pkg) msg = _('File conflicts:\n\"{}\"').format(file_conflicts_str) ctx.ui.warning(msg) if not self.ignore_file_conflicts: if not ctx.ui.confirm(_('Do you want to overwrite it?')): raise Error(msg)
def unpack_dir(self, target_dir, callback=None): rmode = "" self.tar = None if self.type == 'tar': rmode = 'r:' elif self.type == 'targz': rmode = 'r:gz' elif self.type == 'tarbz2': rmode = 'r:bz2' elif self.type in ('tarlzma', 'tarxz'): self.tar = TarFile.lzmaopen(self.file_path, fileobj=self.fileobj) else: raise UnknownArchiveType if self.tar is None: self.tar = tarfile.open(self.file_path, rmode, fileobj=self.fileobj, errorlevel=1) oldwd = None try: # Don't fail if CWD doesn't exist (#6748) oldwd = os.getcwd() except OSError: pass ctx.ui.info(_("Target DIR: \"{}\"").format(target_dir), verbose=True) os.chdir(target_dir) for tarinfo in self.tar: ctx.ui.info(_("Extracting: /{}").format(tarinfo.name),verbose=True) if callback: callback(tarinfo, extracted=False) startservices = [] if tarinfo.issym() and \ os.path.isdir(tarinfo.name) and \ not os.path.islink(tarinfo.name): # Changing a directory with a symlink. tarfile module # cannot handle this case. if os.path.isdir(tarinfo.linkname): # Symlink target is a directory. Move old directory's # content to this directory. for filename in os.listdir(tarinfo.name): old_path = util.join_path(tarinfo.name, filename) new_path = util.join_path(tarinfo.linkname, filename) if os.path.lexists(new_path): if not os.path.isdir(new_path): # A file with the same name exists in the # target. Remove the one in the old directory. os.remove(old_path) continue # try as up to this time try: os.renames(old_path, new_path) except OSError as e: # something gone wrong? [Errno 18] Invalid cross-device link? # try in other way if e.errno == errno.EXDEV: if tarinfo.linkname.startswith(".."): new_path = util.join_path( os.path.normpath( os.path.join( os.path.dirname( tarinfo.name), tarinfo.linkname)), filename) if not old_path.startswith("/"): old_path = "/" + old_path if not new_path.startswith("/"): new_path = "/" + new_path ctx.ui.info("Moving:", old_path, " -> ", new_path) os.system( "mv -f {0} {1}".format(old_path, new_path)) else: raise try: os.rmdir(tarinfo.name) except OSError as e: # hmmm, not empty dir? try rename it adding .old # extension. if e.errno == errno.ENOTEMPTY: # if directory with dbus/pid file was moved we have # to restart dbus for (path, dirs, files) in os.walk(tarinfo.name): if path.endswith("dbus") and "pid" in files: startservices.append("dbus") for service in ( "NetworkManager", "connman", "wicd"): # FIXME: It needs a quick fix for # openrc if os.path.isfile( "/etc/scom/services/enabled/{}".format(service)): startservices.append(service) os.system( "service {} stop".format(service)) os.system("service dbus stop") break os.system("mv -f {0} {0}.old".format(tarinfo.name)) else: raise elif not os.path.lexists(tarinfo.linkname): # Symlink target does not exist. Assume the old # directory is moved to another place in package. try: os.renames(tarinfo.name, tarinfo.linkname) except OSError as e : ctx.ui.warning(str(e)) else: # This should not happen. Probably a packaging error. # Try to rename directory try: os.rename(tarinfo.name, "{}.renamed-by-inary".format(tarinfo.name)) except BaseException: # If fails, try to remove it shutil.rmtree(tarinfo.name) try: if not os.path.isdir(tarinfo.name) and not os.path.islink(tarinfo.name): try: os.unlink(tarinfo.name) except Exception: # TODO: review this block pass self.tar.extract(tarinfo) except OSError as e: # Handle the case where an upper directory cannot # be created because of a conflict with an existing # regular file or symlink. In this case, remove # the old file and retry extracting. if e.errno != errno.EEXIST: raise # For the path "a/b/c", upper_dirs will be ["a", "a/b"]. upper_dirs = [] head, tail = os.path.split(tarinfo.name) while head and tail: upper_dirs.insert(0, head) head, tail = os.path.split(head) for path in upper_dirs: if not os.path.lexists(path): break if not os.path.isdir(path): # A file with the same name exists. # Remove the existing file. os.remove(path) break else: # No conflicts detected! This is probably not the case # mentioned here. Raise the same exception. raise # Try to extract again. self.tar.extract(tarinfo) # Handle the case where new path is file, but old path is directory # due to not possible touch file c in /a/b if directory /a/b/c # exists. if not e.errno == errno.EISDIR: path = tarinfo.name found = False while path: if os.path.isfile(path): os.unlink(path) found = True break else: path = "/".join(path.split("/")[:-1]) if not found: raise # Try to extract again. self.tar.extract(tarinfo) else: shutil.rmtree(tarinfo.name) # Try to extract again. self.tar.extract(tarinfo) # tarfile.extract does not honor umask. It must be honored # explicitly. See --no-same-permissions option of tar(1), # which is the deafult behaviour. # # Note: This is no good while installing a inary package. # Thats why this is optional. try: if os.path.isfile(tarinfo.name): if os.getuid() == 0: os.chown(tarinfo.name, 0, 0) os.chmod(tarinfo.name, tarinfo.mode) # FIXME: We must chmod directory as 755. Empty directory permission is 777. Remove this elif os.path.isdir(tarinfo.name): if os.getuid() == 0: os.chown(tarinfo.name, 0, 0) os.chmod(tarinfo.name, 0o755) else: if os.getuid() == 0: os.lchown(tarinfo.name, 0, 0) except OSError as e: ctx.ui.warning(str(e)) if self.no_same_owner: uid = os.getuid() gid = os.getgid() __chown(tarinfo.name, uid, gid) if not os.path.islink(tarinfo.name): ctx.ui.info( _("Chowning {0} ({1}:{2})").format( tarinfo.name, uid, gid), verbose=True) os.chown(tarinfo.name, uid, gid) else: ctx.ui.info( _("LChowning {0} ({1}:{2})").format( tarinfo.name, uid, gid), verbose=True) os.lchown(tarinfo.name, uid, gid) if callback: callback(tarinfo, extracted=True) try: if oldwd: os.chdir(oldwd) # Bug #6748 except OSError: pass self.close()