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")