Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .coverage
Binary file not shown.
4 changes: 2 additions & 2 deletions debx/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,11 @@ def create_data_tar(self) -> bytes:
with io.BytesIO() as fp:
with tarfile.open(fileobj=fp, mode="w:bz2", format=tarfile.GNU_FORMAT, compresslevel=9) as tar:
for directory_info in self.get_directories():
logging.debug(f"Adding directory to data archive: %s", directory_info.path)
logging.debug("Adding directory to data archive: %s", directory_info.path)
tar.addfile(directory_info)

for item in sorted(self.data_files.values(), key=lambda x: x.tar_info.name):
logging.debug(f"Adding data to archive: %s", item.tar_info.name)
logging.debug("Adding data to archive: %s", item.tar_info.name)
if item.tar_info.type == tarfile.SYMTYPE:
tar.addfile(item.tar_info)
else:
Expand Down
161 changes: 84 additions & 77 deletions debx/cli/inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,90 +19,97 @@
log = logging.getLogger(__name__)


def format_ls(items: list[InspectItem]) -> str:
if not sys.stdout.isatty():
sys.stderr.write(
"Hint: probably you trying process this output. Please see the output formats for better results.\n",
)
def format_size(size: int) -> str:
if size == 0:
return "0B"
size_names = ("B", "K", "M", "G", "T", "P", "E", "Z", "Y")
i = int(math.floor(math.log(size, 1024)))
p = math.pow(1024, i)
s = round(size / p, 1)
if s.is_integer():
s = int(s)
return f"{s}{size_names[i]}"

def format_mode(mode: Optional[int], item_type: Optional[str] = None) -> str:
if mode is None:
return "----------"

result = ""

if item_type is not None:
if item_type == "directory" or (isinstance(item_type, TarInfoType) and item_type == TarInfoType.directory):
result += "d"
elif item_type == "symlink" or (isinstance(item_type, TarInfoType) and item_type == TarInfoType.symlink):
result += "l"
elif item_type == "char" or (isinstance(item_type, TarInfoType) and item_type == TarInfoType.char):
result += "c"
elif item_type == "block" or (isinstance(item_type, TarInfoType) and item_type == TarInfoType.block):
result += "b"
elif item_type == "fifo" or (isinstance(item_type, TarInfoType) and item_type == TarInfoType.fifo):
result += "p"
else:
if stat.S_ISDIR(mode):
result += "d"
elif stat.S_ISLNK(mode):
result += "l"
else:
result += "-"
def _format_size(size: int) -> str:
"""Format size in human-readable format."""
if size == 0:
return "0B"
size_names = ("B", "K", "M", "G", "T", "P", "E", "Z", "Y")
i = int(math.floor(math.log(size, 1024)))
p = math.pow(1024, i)
s = round(size / p, 1)
if s.is_integer():
s = int(s)
return f"{s}{size_names[i]}"


def _format_mode(mode: Optional[int], item_type: Optional[str] = None) -> str:
"""Format file mode as ls-style permission string."""
if mode is None:
return "----------"

result = ""

if item_type is not None:
if item_type == "directory" or (isinstance(item_type, TarInfoType) and item_type == TarInfoType.directory):
result += "d"
elif item_type == "symlink" or (isinstance(item_type, TarInfoType) and item_type == TarInfoType.symlink):
result += "l"
elif item_type == "char" or (isinstance(item_type, TarInfoType) and item_type == TarInfoType.char):
result += "c"
elif item_type == "block" or (isinstance(item_type, TarInfoType) and item_type == TarInfoType.block):
result += "b"
elif item_type == "fifo" or (isinstance(item_type, TarInfoType) and item_type == TarInfoType.fifo):
result += "p"
else:
if stat.S_ISDIR(mode):
result += "d"
elif stat.S_ISLNK(mode):
result += "l"
else:
result += "-"
result += "r" if mode & stat.S_IRUSR else "-"
result += "w" if mode & stat.S_IWUSR else "-"
result += "x" if mode & stat.S_IXUSR else "-"
result += "r" if mode & stat.S_IRGRP else "-"
result += "w" if mode & stat.S_IWGRP else "-"
result += "x" if mode & stat.S_IXGRP else "-"
result += "r" if mode & stat.S_IROTH else "-"
result += "w" if mode & stat.S_IWOTH else "-"
result += "x" if mode & stat.S_IXOTH else "-"
return result

def format_time(mtime: Optional[int], user_locale: Optional[str] = None) -> str:
if mtime is None:
return " "

old_locale = locale.getlocale(locale.LC_TIME)
if user_locale:
try:
locale.setlocale(locale.LC_TIME, user_locale)
except locale.Error:
pass

dt = datetime.datetime.fromtimestamp(mtime)
now = datetime.datetime.now()

if dt.year == now.year:
result = dt.strftime("%d %b %H:%M")
else:
if stat.S_ISDIR(mode):
result += "d"
elif stat.S_ISLNK(mode):
result += "l"
else:
result = dt.strftime("%d %b %Y")
result += "-"
result += "r" if mode & stat.S_IRUSR else "-"
result += "w" if mode & stat.S_IWUSR else "-"
result += "x" if mode & stat.S_IXUSR else "-"
result += "r" if mode & stat.S_IRGRP else "-"
result += "w" if mode & stat.S_IWGRP else "-"
result += "x" if mode & stat.S_IXGRP else "-"
result += "r" if mode & stat.S_IROTH else "-"
result += "w" if mode & stat.S_IWOTH else "-"
result += "x" if mode & stat.S_IXOTH else "-"
return result


def _format_time(mtime: Optional[int], user_locale: Optional[str] = None) -> str:
"""Format modification time in ls-style format."""
if mtime is None:
return " "

old_locale = locale.getlocale(locale.LC_TIME)
if user_locale:
try:
locale.setlocale(locale.LC_TIME, user_locale)
except locale.Error:
pass

dt = datetime.datetime.fromtimestamp(mtime)
now = datetime.datetime.now()

if dt.year == now.year:
result = dt.strftime("%d %b %H:%M")
else:
result = dt.strftime("%d %b %Y")

if user_locale:
try:
locale.setlocale(locale.LC_TIME, old_locale)
except locale.Error:
locale.setlocale(locale.LC_TIME, 'C')

return result

if user_locale:
try:
locale.setlocale(locale.LC_TIME, old_locale)
except locale.Error:
locale.setlocale(locale.LC_TIME, 'C')

return result
def format_ls(items: list[InspectItem]) -> str:
if not sys.stdout.isatty():
sys.stderr.write(
"Hint: probably you trying process this output. Please see the output formats for better results.\n",
)

if not items:
return "total 0"
Expand All @@ -120,11 +127,11 @@ def format_time(mtime: Optional[int], user_locale: Optional[str] = None) -> str:
file_name = item["file"] + "/" + item.get("path", "")
else:
file_name = item["file"]
file_size = format_size(item.get("size", 0))
file_mode = format_mode(item.get("mode", None), item.get("type", None))
file_size = _format_size(item.get("size", 0))
file_mode = _format_mode(item.get("mode", None), item.get("type", None))
file_uid = str(item.get("uid", 0)).rjust(max_uid_len)
file_gid = str(item.get("gid", 0)).rjust(max_gid_len)
file_time = format_time(item.get("mtime", None))
file_time = _format_time(item.get("mtime", None))

path_info = ""
if item.get("path") and item.get("type") == "archive":
Expand Down
51 changes: 48 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,24 +1,59 @@
[project]
name = "debx"
version = "0.2.11"
description = "Minimal Python library to programmatically construct Debian .deb packages"
version = "0.2.12"
description = "Minimal Python library to programmatically construct and inspect Debian .deb packages"
readme = "README.md"
authors = [
{ name = "Dmitry Orlov", email = "me@mosquito.su" }
]
license = "MIT"
license-files = ["COPYING"]
requires-python = ">=3.10"
keywords = [
"administrator",
"apt",
"ar",
"archive",
"automation",
"build",
"cross-platform",
"deb",
"debian",
"development",
"devops",
"dpkg",
"infrastructure",
"library",
"linux",
"macos",
"package",
"packaging",
"system",
"tool",
"windows",
]

classifiers = [
"Development Status :: 3 - Alpha",
"Development Status :: 5 - Production/Stable",
"Environment :: Console",
"Intended Audience :: Developers",
"Intended Audience :: Information Technology",
"Intended Audience :: System Administrators",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Operating System :: POSIX :: Linux",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Topic :: Software Development :: Build Tools",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: System :: Archiving :: Packaging",
"Topic :: System :: Installation/Setup",
"Topic :: System :: Software Distribution",
"Typing :: Typed",
]

Expand All @@ -34,6 +69,7 @@ dev = [
"markdown-pytest>=0.3.2",
"pytest>=9.0.2",
"pytest-cov>=7.0.0",
"ruff>=0.14.10",
]

[project.urls]
Expand All @@ -44,3 +80,12 @@ dev = [

[project.scripts]
"debx" = "debx.__main__:main"

[tool.coverage.run]
branch = true
source = ["debx"]

[tool.coverage.report]
exclude_lines = [
"if __name__ == .__main__.:",
]
Loading