extracting archive in gridftp
authorMaciej Tronowski <mtro@man.poznan.pl>
Mon, 13 Apr 2015 16:27:35 +0000 (18:27 +0200)
committerMaciej Tronowski <mtro@man.poznan.pl>
Mon, 13 Apr 2015 16:27:35 +0000 (18:27 +0200)
filex/ftp.py
filex/urls.py
filex/views.py
qcg/templates/qcg/gridftp.html

index c2f3b3a..39ee807 100644 (file)
@@ -154,18 +154,19 @@ class FTPOperation:
 
         self.wait()
 
-    def compress(self, server, path, files, archive):
-        def match_ext(*extensions):
-            for ext in extensions:
-                if archive.endswith(ext):
-                    return True
-            return False
+    @staticmethod
+    def match_ext(archive, *extensions):
+        for ext in extensions:
+            if archive.endswith(ext):
+                return True
+        return False
 
-        if match_ext('.tar.gz', '.tgz'):
+    def compress(self, server, path, files, archive):
+        if self.match_ext(archive, '.tar.gz', '.tgz'):
             cmd, args = 'tar', ['cvzf', os.path.join(path, archive), '-C', path] + files
-        elif match_ext('.tar.bz2', '.tbz'):
+        elif self.match_ext(archive, '.tar.bz2', '.tbz'):
             cmd, args = 'tar', ['cvjf', os.path.join(path, archive), '-C', path] + files
-        elif match_ext('.zip'):
+        elif self.match_ext(archive, '.zip'):
             cmd, args = 'zip', ['-r', os.path.join(path, archive)] + [os.path.join(path, f) for f in files]
         else:
             raise ValueError('Unknown archive type: {}'.format(archive))
@@ -174,3 +175,18 @@ class FTPOperation:
         self.op_attr.set_disk_stack('#'.join(["popen:argv=", cmd] + args))
 
         return self.get(server)
+
+    def extract(self, server, archive, dst):
+        if self.match_ext(archive, '.tar.gz', '.tgz'):
+            cmd, args = 'tar', ['xvzf', archive, '-C', dst]
+        elif self.match_ext(archive, '.tar.bz2', '.tbz'):
+            cmd, args = 'tar', ['xvjf', archive, '-C', dst]
+        elif self.match_ext(archive, '.zip'):
+            cmd, args = 'unzip', [archive, '-d', dst]
+        else:
+            raise ValueError('Unknown archive type: {}'.format(archive))
+
+        # FIXME handling filename with #
+        self.op_attr.set_disk_stack('#'.join(["popen:argv=", cmd] + args))
+
+        return self.get(server)
index 2221c26..883b8b4 100644 (file)
@@ -11,4 +11,5 @@ urlpatterns = patterns('',
     url(r'^mkdir/$', views.mkdir, name='mkdir'),
     url(r'^move/$', views.move, name='move'),
     url(r'^compress/$', views.compress, name='compress'),
+    url(r'^extract/$', views.extract, name='extract'),
 )
index 1a02ddb..a85c265 100644 (file)
@@ -197,7 +197,7 @@ def compress(request):
     path = request.POST.get('path')
     files = request.POST.getlist('files')
     archive = request.POST.get('archive')
-    if not host or not path or not files:
+    if not host or not path or not files or not archive:
         raise SuspiciousOperation("No path or host or files or archive given!")
 
     server = 'gsiftp://' + host
@@ -209,3 +209,25 @@ def compress(request):
         return JsonResponse({'msg': e.message}, status=400)
     else:
         return JsonResponse({'success': True})
+
+
+@require_POST
+def extract(request):
+    check_auth(request)
+
+    # TODO data validation
+    host = request.POST.get('host')
+    archive = request.POST.get('archive')
+    dst = request.POST.get('dst')
+    if not host or not archive or not dst:
+        raise SuspiciousOperation("No path or host or files or archive given!")
+
+    server = 'gsiftp://' + host
+
+    try:
+        # consume generator with command output
+        list(FTPOperation(request.session['proxy']).extract(server, archive, dst))
+    except FTPException as e:
+        return JsonResponse({'msg': e.message}, status=400)
+    else:
+        return JsonResponse({'success': True})
index 9b354de..dd24d7e 100644 (file)
         $(function () {
             var statusTimeout;
 
+            String.prototype.endsWith = function(suffix) {
+                return this.indexOf(suffix, this.length - suffix.length) !== -1;
+            };
+
             function status(msg) {
                 clearTimeout(statusTimeout);
                 statusTimeout = setTimeout(function() {
@@ -23,9 +27,9 @@
                 $('#status').text(msg);
             }
 
-            function fail(xhr) {
-                status('Wystąpił błąd: ' + ((xhr.responseJSON || {}).msg || "Server error"));
-                console.error(xhr);
+            function fail() {
+                status('Wystąpił błąd.');
+                console.error(arguments);
                 filex.idle();
             }
 
                 $('#btn-rename').toggleClass('disabled', selected != 1);
                 $('#btn-delete').toggleClass('disabled', selected == 0);
                 $('#btn-compress').toggleClass('disabled', selected == 0);
-                $('#btn-extract').toggleClass('disabled', selected != 1);
+
+                if (selected == 1) {
+                    var filename = filex.selectedFiles()[0].get('name'),
+                        is_archive = _.some(['.zip', '.tar.gz', '.tgz', '.tar.bz2', 'tbz'], function(ext) {
+                            return filename.endsWith(ext);
+                        });
+
+                    $('#btn-extract').toggleClass('disabled', !is_archive);
+                }
+                else {
+                    $('#btn-extract').toggleClass('disabled', true);
+                }
             });
 
             $('#btn-upload').on('click', function() {
                 $this.find('#id_host').val(filex.host);
                 $this.find('#id_path').val(filex.path.full());
 
-                $.post($this.attr('action'), $this.serialize(), function(response) {
+                $.post($this.attr('action'), $this.serialize(), function() {
                     status('Katalog utworzono pomyślnie');
                     filex.reloadFiles();
                 }, 'json').fail(fail);
                 filex.busy();
                 $this.modal('hide');
 
-                $.post($this.attr('action'), $this.serialize(), function(response) {
+                $.post($this.attr('action'), $this.serialize(), function() {
                     status('Nazwę zmieniono pomyślnie');
                     filex.reloadFiles();
                 }, 'json').fail(fail);
                 var $this = $(this),
                     name = $this.find('#id_name').val(),
                     type = $this.find('#id_type').val(),
-                    archive = name + (name.indexOf(type, name.length - type.length) === -1 ? type : ''),
+                    archive = name + (name.endsWith(type) ? '' : type),
                     data = {
                         host: filex.host,
                         path: filex.path.full(),
                 filex.busy();
                 $this.modal('hide');
 
-                $.post($this.attr('action'), data, function(response) {
+                $.post($this.attr('action'), data, function() {
                     status('Archiwum utworzono pomyślnie');
                     filex.reloadFiles();
                 }, 'json').fail(fail);
             });
+
+            $('#btn-extract').on('click', function() {
+                filex.busy();
+
+                var data = {
+                    host: filex.host,
+                    archive: filex.path.full() + '/' + filex.selectedFiles()[0].get('name'),
+                    dst: filex.path.full()
+                };
+
+                $.post('{% url 'filex:extract' %}', data, function() {
+                    status('Archiwum rozpakowano pomyślnie');
+                    filex.reloadFiles();
+                }, 'json').fail(fail);
+            });
         })
     </script>
 {% endblock extra_js %}