def _normpath(path): """ Replace all symlink in path with real path and return its absolute path For example, if given path is "local/bin/python" and "local" is a symbolic link to "/usr/local", returned path will be "/usr/local/bin/python" """ if hasattr(os, 'readlink'): parts = Path(path).splitall() _path = Path('') for p in parts: _path = _path / p if _path.islink(): # readlink return an absolute path or relative path depending on symlink. # If symlink is a relative link, parent path is used to generate an absolute path # Default path behaviour when concatenating two absolute paths is to keep only second one: # path('/a/1')/path('/b/2') -> path('/b/2') # So, if symlink is absolute, all is ok _path = _path.parent / _path.readlink() return _path.abspath() else: return path.abspath()
def _add_item(self, category, obj=None, **kwargs): mode = kwargs.pop('mode', self.MODE_COPY) if obj and isinstance(obj, Data): # TODO: Check obj follow Data or Model interface ?? new_path = self.path / category / obj.path.name if obj.path != new_path and mode == self.MODE_COPY: # TODO: use Data.copy instead return self._add_item(category, path=obj.path, **kwargs) category_dict = getattr(self, category) if obj.filename not in category_dict: category_dict[str(obj.filename)] = obj else: raise ValueError("data '%s' already exists in project '%s'" % (obj.filename, self.alias)) elif obj: category_dict = getattr(self, category) if obj.name not in category_dict: category_dict[str(obj.name)] = obj else: raise ValueError("data '%s' already exists in project '%s'" % (obj.name, self.alias)) else: filename = Path( kwargs.pop('filename')) if 'filename' in kwargs else None content = kwargs.pop('content', None) dtype = kwargs.pop('dtype', None) mimetype = kwargs.pop('mimetype', None) path = Path(kwargs.pop('path')) if 'path' in kwargs else None # If project path exists, ie project exists on disk, # Create category dir if necessary category_path = self.path / category if self.path.exists() and not category_path.exists(): category_path.makedirs() if filename: new_path = self.path / category / filename.name elif path: if not path.exists(): raise ErrorInvalidItem("path '%s' doesn't exists" % path) filename = path.name new_path = self.path / category / filename else: raise ValueError("path or filename required") if path is None: path = new_path # If data was outside project, we try to fix it. # If mode is "prefer copy", we try to copy file inside project # If copy fails, we get original content and pass it to new data # If mode is "prefer link", we just keep original path (keep outside project) # TODO: Move to Data.copy data_obj = None if new_path.abspath() != path.abspath() and mode == self.MODE_COPY: try: path.copyfile(new_path) except IOError: data_obj = DataFactory(path, mimetype, dtype=dtype, default_content=content) content = data_obj.read() else: content = None elif new_path.abspath() != path.abspath( ) and mode == self.MODE_LINK: new_path = path else: pass # Nothing to do, data is yet in the right place data_obj = DataFactory(new_path, mimetype, dtype=dtype, default_content=content) obj = self._add_item(category, data_obj, **kwargs) obj.package = self return obj
def _add_item(self, category, obj=None, **kwargs): mode = kwargs.pop('mode', self.MODE_COPY) if obj and isinstance(obj, Data): # TODO: Check obj follow Data or Model interface ?? new_path = self.path / category / obj.path.name if obj.path != new_path and mode == self.MODE_COPY: # TODO: use Data.copy instead return self._add_item(category, path=obj.path, **kwargs) category_dict = getattr(self, category) if obj.filename not in category_dict: category_dict[str(obj.filename)] = obj else: raise ValueError("data '%s' already exists in project '%s'" % (obj.filename, self.alias)) elif obj: category_dict = getattr(self, category) if obj.name not in category_dict: category_dict[str(obj.name)] = obj else: raise ValueError("data '%s' already exists in project '%s'" % (obj.name, self.alias)) else: filename = Path(kwargs.pop('filename')) if 'filename' in kwargs else None content = kwargs.pop('content', None) dtype = kwargs.pop('dtype', None) mimetype = kwargs.pop('mimetype', None) path = Path(kwargs.pop('path')) if 'path' in kwargs else None # If project path exists, ie project exists on disk, # Create category dir if necessary category_path = self.path / category if self.path.exists() and not category_path.exists(): category_path.makedirs() if filename: new_path = self.path / category / filename.name elif path: if not path.exists(): raise ErrorInvalidItem("path '%s' doesn't exists" % path) filename = path.name new_path = self.path / category / filename else: raise ValueError("path or filename required") if path is None: path = new_path # If data was outside project, we try to fix it. # If mode is "prefer copy", we try to copy file inside project # If copy fails, we get original content and pass it to new data # If mode is "prefer link", we just keep original path (keep outside project) # TODO: Move to Data.copy data_obj = None if new_path.abspath() != path.abspath() and mode == self.MODE_COPY: try: path.copyfile(new_path) except IOError: data_obj = DataFactory(path, mimetype, dtype=dtype, default_content=content) content = data_obj.read() else: content = None elif new_path.abspath() != path.abspath() and mode == self.MODE_LINK: new_path = path else: pass # Nothing to do, data is yet in the right place data_obj = DataFactory(new_path, mimetype, dtype=dtype, default_content=content) obj = self._add_item(category, data_obj, **kwargs) obj.package = self return obj