Home > OS >  The `File is not a zip file` error for the output of `git show` by GitPython
The `File is not a zip file` error for the output of `git show` by GitPython

Time:04-01

The script to reproduce the issue

Save this code as a shell script and run it. The code should report the File is not a zip file error.

#!/bin/bash

set -eu

mkdir foo
cd foo

pip install --user GitPython

echo foo > a
zip a.zip a

# -t option validates the zip file.
# See https://unix.stackexchange.com/questions/197127/test-integrity-of-zip-file
unzip -t a.zip

git init
git add a.zip
git commit -m 'init commit'

cat << EOF > test.py
from git import Repo
import zipfile
from io import StringIO

repo = Repo('.', search_parent_directories=True)

raw = repo.git.show("HEAD:a.zip")

z = zipfile.ZipFile(StringIO(raw), "r")
EOF

python3 test.py

Original Question

I'm writing a Krita plugin for viewing files in previous commits of a Git repository, and I want to get the thumbnail file of a Krita file. To do so, I'm trying to get a file with git show, unzip it because a Krita file is a Zip file, and get preview.png or mergedimage.png.

%unzip image.kra
Archive:  image.kra
 extracting: mimetype                
  inflating: maindoc.xml             
  inflating: documentinfo.xml        
  inflating: preview.png             
  inflating: image/layers/layer2     
  inflating: image/layers/layer2.defaultpixel  
  inflating: image/layers/layer2.icc  
  inflating: image/annotations/icc   
  inflating: mergedimage.png         
  inflating: image/animation/index.xml  

We can get the .kra file from the Git repository as str with GitPython. However, I can't parse the file with zipfile.ZipFile as it says File is not a zip file. (This code is based on this SO answer)

from git import Repo
import zipfile
from io import StringIO

repo = Repo('.', search_parent_directories=True)

raw = repo.git.show("HEAD~:image.kra")

z = zipfile.ZipFile(StringIO(raw), "r")

will emit

Traceback (most recent call last):
  File "/home/hiroki/krita_question/test.py", line 11, in <module>
    z = zipfile.ZipFile(StringIO(raw), "r")
  File "/usr/lib/python3.9/zipfile.py", line 1257, in __init__
    self._RealGetContents()
  File "/usr/lib/python3.9/zipfile.py", line 1324, in _RealGetContents
    raise BadZipFile("File is not a zip file")
zipfile.BadZipFile: File is not a zip file

I believe this is a valid Krita file because I can restore the file with git show on the command line. So,

%git show HEAD~:image.kra > prev.kra
%krita prev.kra

works correctly. Unzipping the file works too.

Why can't I parse the git show output as a Zip file?

git log --stat|grep -v 'Author':

commit b96d915862b39a204a9f4350e7e56634b6fcfe0b
Date:   Wed Mar 30 14:44:02 2022  0900

    chore: add

 ls | 231                                                                      
 1 file changed, 231 insertions( )

commit 619984a842c6c2daf31559c1979f91227a323648
Date:   Wed Mar 30 14:43:58 2022  0900

    chore: add

 image.kra | Bin 0 -> 777685 bytes
 1 file changed, 0 insertions( ), 0 deletions(-)

Versions

Python: 3.9.9

GitPython: 3.1.27

Krita: 5.0.2

Linux 5.15.16-gentoo

All files are created in Linux.

CodePudding user response:

It seems that this is caused by the GitPython's bug. It truncated the last \n of the output of git show and made the file invalid.

I changed the code to use subprocess.Popen and ZipFile succeeded.

import zipfile
from io import BytesIO
import subprocess

p = subprocess.Popen(["git", "show", "HEAD:a.zip"], stdout = subprocess.PIPE)

out, _ = p.communicate()

z = zipfile.ZipFile(BytesIO(out), "r")
  • Related