Skip to content

Commit 6a4e5e0

Browse files
authored
Merge pull request #145 from roman-captural/abstract-filesystems
Rewrite of storage backend using fs
2 parents 6d7869c + f7f5cfa commit 6a4e5e0

File tree

10 files changed

+196
-153
lines changed

10 files changed

+196
-153
lines changed

Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ FROM docker.io/debian:buster-slim
33
# install imagetagger system dependencies
44
RUN apt-get update && \
55
apt-get install --no-install-recommends -y g++ wget uwsgi-plugin-python3 python3 python3-pip node-uglify make git \
6-
python3-psycopg2 python3-ldap3 gettext gcc python3-dev python3-setuptools libldap2-dev libsasl2-dev nginx
6+
python3-psycopg2 python3-ldap3 python3-pkg-resources gettext gcc python3-dev python3-setuptools libldap2-dev \
7+
libsasl2-dev nginx
78

89
# add requirements file
910
WORKDIR /app/src
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import fs
2+
import fs.base
3+
from django.conf import settings
4+
5+
6+
def root() -> fs.base.FS:
7+
"""Get the root filesystem object or create one by opening `settings.FS_URL`."""
8+
if root._instance is None:
9+
root._instance = fs.open_fs(settings.FS_URL)
10+
return root._instance
11+
12+
root._instance = None
13+
14+
15+
def tmp() -> fs.base.FS:
16+
"""Get the tmp filesystem object or create one by opening `settings.TMP_FS_URL`."""
17+
if tmp._instance is None:
18+
tmp._instance = fs.open_fs(settings.TMP_FS_URL)
19+
return tmp._instance
20+
21+
tmp._instance = None

imagetagger/imagetagger/images/management/commands/runzipdaemon.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import fasteners
2-
import os
2+
from fs import path
3+
from fs.zipfs import WriteZipFS
34
from time import sleep
45

56
from django.conf import settings
67
from django.core.management import BaseCommand, CommandError
78
from django.db.models import Q
8-
from zipfile import ZipFile
99

1010
from imagetagger.images.models import ImageSet
11+
from imagetagger.base.filesystem import root, tmp
1112

1213

1314
class Command(BaseCommand):
@@ -17,7 +18,7 @@ def handle(self, *args, **options):
1718
if not settings.ENABLE_ZIP_DOWNLOAD:
1819
raise CommandError('To enable zip download, set ENABLE_ZIP_DOWNLOAD to True in settings.py')
1920

20-
lock = fasteners.InterProcessLock(os.path.join(settings.IMAGE_PATH, 'zip.lock'))
21+
lock = fasteners.InterProcessLock(path.combine(settings.IMAGE_PATH, 'zip.lock'))
2122
gotten = lock.acquire(blocking=False)
2223
if gotten:
2324
while True:
@@ -37,12 +38,16 @@ def _regenerate_zip(self, imageset):
3738
self.stderr.write('skipping regeneration of ready imageset {}'.format(imageset.name))
3839
return
3940

40-
with ZipFile(os.path.join(settings.IMAGE_PATH, imageset.tmp_zip_path()), 'w') as f:
41-
for image in imageset.images.all():
42-
f.write(image.path(), image.name)
43-
44-
os.rename(os.path.join(settings.IMAGE_PATH, imageset.tmp_zip_path()),
45-
os.path.join(settings.IMAGE_PATH, imageset.zip_path()))
41+
tmp_zip_path = imageset.tmp_zip_path()
42+
if not tmp().exists(path.dirname(tmp_zip_path)):
43+
tmp().makedirs(path.dirname(tmp_zip_path))
44+
with tmp().open(tmp_zip_path, 'wb') as zip_file:
45+
with WriteZipFS(zip_file) as zip_fs:
46+
for image in imageset.images.all():
47+
root().download(image.path(), zip_fs.openbin(image.name, 'w'))
48+
with tmp().open(tmp_zip_path, 'rb') as zip_file:
49+
root().upload(imageset.zip_path(), zip_file)
50+
tmp().remove(tmp_zip_path)
4651

4752
# Set state to ready if image set has not been set to invalid during regeneration
4853
ImageSet.objects.filter(pk=imageset.pk, zip_state=ImageSet.ZipState.PROCESSING) \

imagetagger/imagetagger/images/models.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
from typing import Set
22

3+
from fs import path
34
from django.conf import settings
45
from django.contrib.auth import get_user_model
56
from django.db import models
6-
import os
77

88
from imagetagger.users.models import Team
99

@@ -19,10 +19,10 @@ class Image(models.Model):
1919
height = models.IntegerField(default=600)
2020

2121
def path(self):
22-
return os.path.join(self.image_set.root_path(), self.filename)
22+
return path.combine(self.image_set.root_path(), self.filename)
2323

2424
def relative_path(self):
25-
return os.path.join(self.image_set.path, self.filename)
25+
return path.combine(self.image_set.path, self.filename)
2626

2727
def delete(self, *args, **kwargs):
2828
self.image_set.zip_state = ImageSet.ZipState.INVALID
@@ -92,17 +92,23 @@ class ZipState:
9292
zip_state = models.IntegerField(choices=ZIP_STATES, default=ZipState.INVALID)
9393

9494
def root_path(self):
95-
return os.path.join(settings.IMAGE_PATH, self.path)
95+
return path.combine(settings.IMAGE_PATH, self.path)
96+
97+
def tmp_path(self):
98+
return path.combine(settings.TMP_IMAGE_PATH, self.path)
99+
100+
def relative_zip_path(self):
101+
return path.combine(self.path, self.zip_name())
96102

97103
def zip_path(self):
98-
return os.path.join(self.path, self.zip_name())
104+
return path.combine(self.root_path(), self.zip_name())
105+
106+
def tmp_zip_path(self):
107+
return path.combine(self.tmp_path(), self.zip_name())
99108

100109
def zip_name(self):
101110
return "imageset_{}.zip".format(self.id)
102111

103-
def tmp_zip_path(self):
104-
return os.path.join(self.path, ".tmp." + self.zip_name())
105-
106112
@property
107113
def image_count(self):
108114
if hasattr(self, 'image_count_agg'):

0 commit comments

Comments
 (0)