Răsfoiți Sursa

Add xz support

clanker 1 lună în urmă
părinte
comite
173282750a
4 a modificat fișierele cu 178 adăugiri și 11 ștergeri
  1. 16 2
      src/autusm/extractor.py
  2. 5 0
      src/autusm/generator.py
  3. 1 9
      src/autusm/usm_integration.py
  4. 156 0
      test_xz_support.py

+ 16 - 2
src/autusm/extractor.py

@@ -2,7 +2,7 @@
 Archive extractor for autusm.
 
 This module provides functionality to extract various archive formats
-including tar, tar.gz, tar.bz2, and zip.
+including tar, tar.gz, tar.bz2, tar.xz, and zip.
 """
 
 import os
@@ -29,6 +29,8 @@ class ArchiveExtractor:
             '.tgz': self._extract_tar_gz,
             '.tar.bz2': self._extract_tar_bz2,
             '.tbz2': self._extract_tar_bz2,
+            '.tar.xz': self._extract_tar_xz,
+            '.txz': self._extract_tar_xz,
             '.zip': self._extract_zip,
         }
 
@@ -142,6 +144,18 @@ class ArchiveExtractor:
             self._check_tar_security(tar)
             tar.extractall(destination)
 
+    def _extract_tar_xz(self, archive_path: Path, destination: Path) -> None:
+        """Extract a xz-compressed tar archive.
+        
+        Args:
+            archive_path: Path to the tar.xz archive
+            destination: Directory to extract to
+        """
+        with tarfile.open(archive_path, 'r:xz') as tar:
+            # Check for security issues
+            self._check_tar_security(tar)
+            tar.extractall(destination)
+
     def _extract_zip(self, archive_path: Path, destination: Path) -> None:
         """Extract a zip archive.
         
@@ -258,7 +272,7 @@ class ArchiveExtractor:
             if not archive_format:
                 raise ExtractionError(f"Unsupported archive format: {archive_path}")
             
-            if archive_format in ['.tar', '.tar.gz', '.tgz', '.tar.bz2', '.tbz2']:
+            if archive_format in ['.tar', '.tar.gz', '.tgz', '.tar.bz2', '.tbz2', '.tar.xz', '.txz']:
                 with tarfile.open(archive_path, 'r:*') as tar:
                     return tar.getnames()
             elif archive_format == '.zip':

+ 5 - 0
src/autusm/generator.py

@@ -91,6 +91,7 @@ detect_archive_type() {{
     case "$filename" in
         *.tar.gz|*.tgz) echo "tar.gz" ;;
         *.tar.bz2|*.tbz2) echo "tar.bz2" ;;
+        *.tar.xz|*.txz) echo "tar.xz" ;;
         *.tar) echo "tar" ;;
         *.zip) echo "zip" ;;
         *) echo "unknown" ;;
@@ -131,6 +132,10 @@ extract_archive() {{
             # Use --strip-components=1 to remove the top-level directory
             tar -xjf "$archive" -C "$extract_to" --strip-components=1
             ;;
+        tar.xz|txz)
+            # Use --strip-components=1 to remove the top-level directory
+            tar -xJf "$archive" -C "$extract_to" --strip-components=1
+            ;;
         tar)
             # Use --strip-components=1 to remove the top-level directory
             tar -xf "$archive" -C "$extract_to" --strip-components=1

+ 1 - 9
src/autusm/usm_integration.py

@@ -64,10 +64,8 @@ class USMIntegration:
                 timeout=300  # 5 minutes timeout
             )
             
-            # Log stdout and stderr separately to ensure no contamination
+            # Log command result separately to ensure no contamination
             logger.debug(f"USM command exit code: {result.returncode}")
-            logger.debug(f"USM stdout (for parsing): {repr(result.stdout)}")
-            logger.debug(f"USM stderr (debug info): {repr(result.stderr)}")
             
             # Always log stderr separately for debugging but don't mix with stdout
             if result.stderr:
@@ -88,7 +86,6 @@ class USMIntegration:
                 return {}
             
             # Parse only the stdout output
-            logger.debug(f"Parsing USM stdout output: {repr(result.stdout)}")
             autoprovides = self._parse_autoprovides(result.stdout)
             
             logger.info(f"Got {len(autoprovides)} autoprovides from USM")
@@ -119,7 +116,6 @@ class USMIntegration:
         try:
             # Check if stdout output looks like valid JSON
             stdout_output = stdout_output.strip()
-            logger.debug(f"Trimmed stdout output for parsing: {repr(stdout_output)}")
             
             if not stdout_output:
                 logger.warning("Empty autoprovides stdout output")
@@ -132,11 +128,9 @@ class USMIntegration:
                     # Extract the JSON content between the braces
                     # Everything after the opening brace and before the closing brace
                     json_content = stdout_output[len('"provides": {'):-1].strip()
-                    logger.debug(f"Extracted JSON content: {repr(json_content)}")
                     
                     # Parse the extracted content as JSON
                     json_data = json.loads('{' + json_content + '}')
-                    logger.debug(f"Successfully parsed extracted JSON: {json_data}")
                     
                     # Validate that we have a proper JSON structure
                     if not isinstance(json_data, dict):
@@ -195,10 +189,8 @@ class USMIntegration:
             
             # Try to parse as JSON first (original logic)
             if stdout_output.startswith('{') and stdout_output.endswith('}'):
-                logger.debug("Stdout output looks like JSON, attempting to parse")
                 try:
                     json_data = json.loads(stdout_output)
-                    logger.debug(f"Successfully parsed JSON: {json_data}")
                     
                     # Validate that we have a proper JSON structure
                     if not isinstance(json_data, dict):

+ 156 - 0
test_xz_support.py

@@ -0,0 +1,156 @@
+#!/usr/bin/env python3
+"""
+Test script to verify XZ archive support in autusm.
+
+This script tests that .tar.xz archives can be properly detected and extracted.
+"""
+
+import os
+import sys
+import tempfile
+import tarfile
+from pathlib import Path
+
+# Add the src directory to the path so we can import autusm modules
+sys.path.insert(0, str(Path(__file__).parent / "src"))
+
+from autusm.extractor import ArchiveExtractor
+from autusm.generator import ScriptGenerator
+from autusm.models import PackageInfo, BuildSystem, BuildSystemType
+
+
+def create_test_xz_archive(archive_path: Path) -> None:
+    """Create a test .tar.xz archive with some sample files.
+    
+    Args:
+        archive_path: Path where to create the archive
+    """
+    # Create a temporary directory with test files
+    with tempfile.TemporaryDirectory() as temp_dir:
+        temp_path = Path(temp_dir)
+        test_dir = temp_path / "test_package"
+        test_dir.mkdir()
+        
+        # Create some test files
+        (test_dir / "README.md").write_text("# Test Package\nThis is a test package.")
+        (test_dir / "configure").write_text("#!/bin/sh\necho 'Configuring...'")
+        (test_dir / "Makefile").write_text("all:\n\techo 'Building...'")
+        
+        # Create the tar.xz archive
+        with tarfile.open(archive_path, 'w:xz') as tar:
+            tar.add(test_dir, arcname="test_package")
+
+
+def test_xz_detection():
+    """Test that .tar.xz archives are properly detected."""
+    print("Testing XZ archive detection...")
+    
+    extractor = ArchiveExtractor()
+    
+    # Test with .tar.xz extension
+    assert extractor._detect_format(Path("test.tar.xz")) == ".tar.xz", "Failed to detect .tar.xz"
+    
+    # Test with .txz extension
+    assert extractor._detect_format(Path("test.txz")) == ".txz", "Failed to detect .txz"
+    
+    print("✓ XZ archive detection test passed")
+
+
+def test_xz_extraction():
+    """Test that .tar.xz archives can be properly extracted."""
+    print("Testing XZ archive extraction...")
+    
+    extractor = ArchiveExtractor()
+    
+    with tempfile.TemporaryDirectory() as temp_dir:
+        temp_path = Path(temp_dir)
+        archive_path = temp_path / "test.tar.xz"
+        extract_dir = temp_path / "extracted"
+        
+        # Create a test XZ archive
+        create_test_xz_archive(archive_path)
+        
+        # Extract the archive
+        extractor.extract(archive_path, extract_dir)
+        
+        # Verify extraction
+        assert extract_dir.exists(), "Extraction directory was not created"
+        assert (extract_dir / "README.md").exists(), "README.md was not extracted"
+        assert (extract_dir / "configure").exists(), "configure was not extracted"
+        assert (extract_dir / "Makefile").exists(), "Makefile was not extracted"
+        
+        # Verify content
+        readme_content = (extract_dir / "README.md").read_text()
+        assert "Test Package" in readme_content, "README content is incorrect"
+    
+    print("✓ XZ archive extraction test passed")
+
+
+def test_generator_xz_support():
+    """Test that the generator includes XZ support in acquire scripts."""
+    print("Testing generator XZ support...")
+    
+    generator = ScriptGenerator()
+    package_info = PackageInfo(name="test_package", url="http://example.com/test.tar.xz")
+    build_system = BuildSystem(type=BuildSystemType.AUTOTOOLS)
+    
+    # Generate the acquire script
+    acquire_script = generator._common_acquire_template(package_info, build_system)
+    
+    # Verify that XZ is included in the detect_archive_type function
+    assert "*.tar.xz|*.txz" in acquire_script, "XZ format not included in detect_archive_type"
+    assert 'echo "tar.xz"' in acquire_script, "XZ case not in detect_archive_type"
+    
+    # Verify that XZ extraction is included in extract_archive function
+    assert "tar.xz|txz)" in acquire_script, "XZ case not in extract_archive"
+    assert "tar -xJf" in acquire_script, "XZ extraction command not found"
+    
+    print("✓ Generator XZ support test passed")
+
+
+def test_list_contents():
+    """Test that we can list contents of a .tar.xz archive."""
+    print("Testing list contents for XZ archives...")
+    
+    extractor = ArchiveExtractor()
+    
+    with tempfile.TemporaryDirectory() as temp_dir:
+        temp_path = Path(temp_dir)
+        archive_path = temp_path / "test.tar.xz"
+        
+        # Create a test XZ archive
+        create_test_xz_archive(archive_path)
+        
+        # List contents
+        contents = extractor.list_contents(archive_path)
+        
+        # Verify contents
+        assert len(contents) > 0, "No contents found in archive"
+        assert any("README.md" in item for item in contents), "README.md not found in contents"
+        assert any("configure" in item for item in contents), "configure not found in contents"
+        assert any("Makefile" in item for item in contents), "Makefile not found in contents"
+    
+    print("✓ List contents test passed")
+
+
+def main():
+    """Run all tests."""
+    print("Running XZ support tests...\n")
+    
+    try:
+        test_xz_detection()
+        test_xz_extraction()
+        test_generator_xz_support()
+        test_list_contents()
+        
+        print("\n✅ All XZ support tests passed!")
+        return 0
+    except Exception as e:
+        print(f"\n❌ Test failed: {e}")
+        import traceback
+        traceback.print_exc()
+        return 1
+
+
+if __name__ == "__main__":
+    sys.exit(main())