From ead23c86f56ae5febe3b6caafac55397929ae6c5 Mon Sep 17 00:00:00 2001 From: Thomas Leonard Date: Thu, 11 Jul 2002 11:51:59 +0000 Subject: [PATCH] Convert to ROX-Lib2. git-svn-id: https://rox.svn.sourceforge.net/svnroot/rox/trunk/Archive@1648 66de3db3-b00d-0410-b41b-f4738ad19bea --- AppInfo.xml | 2 +- AppRun | 304 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- Archive.py | 95 +++---------------- findrox.py | 62 +++++++------ 4 files changed, 337 insertions(+), 126 deletions(-) rewrite AppRun (92%) diff --git a/AppInfo.xml b/AppInfo.xml index 84ce83b..08e90ec 100644 --- a/AppInfo.xml +++ b/AppInfo.xml @@ -4,7 +4,7 @@ Such files usually have names ending in .gz, .tar, .tgz, .bz2, .rar or .zip. Create and read archive files - 0.1.2 (22-May-2001) + 0.1.3 PREVIEW Thomas Leonard GNU General Public License http://rox.sourceforge.net diff --git a/AppRun b/AppRun dissimilarity index 92% index b608455..863cc7f 100755 --- a/AppRun +++ b/AppRun @@ -1,14 +1,290 @@ -#!/usr/bin/env python - -import findrox, sys, os.path - -# To support Gtk+ versions 1.2 and 2.0, add the v1 or v2 subdirectory -# to the modules search path... -try: - from rox2 import support - sys.path.insert(0, os.path.join(support.app_dir, 'v2')) -except: - from rox import support - sys.path.insert(0, os.path.join(support.app_dir, 'v1')) - -import main +#!/usr/bin/env python + +import findrox +import sys, os, formats + +import rox +from rox import g, TRUE, FALSE, saving + +if len(sys.argv) != 2: + rox.info("Drag a file or directory onto Archive to archive it. " + "Drag an archive onto it to extract.") + sys.exit(0) + +def escape(text): + """Return text with \ and ' escaped""" + return text.replace("\\", "\\\\").replace("'", "\\'") + +assert escape(''' a test ''') == ' a test ' +assert escape(''' "a's test" ''') == ''' "a\\'s test" ''' +assert escape(''' "a\\'s test" ''') == ''' "a\\\\\\'s test" ''' + +def Tmp(): + # Protect against DoS attacks + import random + name = `random.randint(1, 1000000)` + '-archive' + + import tempfile + return tempfile.TemporaryFile(suffix = name) + +def pipe_through_command(command, src, dst): + """Execute 'command' with src as stdin (if any) and writing to + stream dst. src must be a fileno() stream.""" + + if dst: + if hasattr(dst, 'fileno'): + tmp_stream = dst + else: + tmp_stream = Tmp() + fd = tmp_stream.fileno() + else: + fd = -1 + + import os + child = os.fork() + if child == 0: + try: + if src: + os.dup2(src.fileno(), 0) + if fd != -1: + os.dup2(fd, 1) + os.system(command) + finally: + os._exit(0) + assert 0 + pid, status = os.waitpid(child, 0) + if status != 0: + rox.alert('Command returned an error!') + return 0 + if dst and tmp_stream is not dst: + print "(loading tmp)" + tmp_stream.seek(0) + data = tmp_stream.read() + print len(data) + tmp_stream.seek(0) + dst.write(tmp_stream.read()) + return 1 + +# Show the savebox, so at least the user knows something is happening.. +class FileData(saving.Saveable): + "A file on the local filesystem." + def __init__(self, path, stream): + self.path = path + self.start = stream.read(300) + try: + stream.seek(0) + self.stream = stream + except: + print "(unseekable)" + # Input is not a regular, local, seekable file, so copy it + # to a local temp file. + import shutil + tmp = Tmp() + tmp.write(self.start) + shutil.copyfileobj(stream, tmp) + self.stream = tmp + + create_arc = () + + create_stream = ( + ('gz', "gzip -c -"), + ('bz2', "bzip2 -c -") + ) + + extract_arc = ( + # Archives + ('tgz', "gunzip -c '%s' | tar xf -"), + ('tar.gz', "gunzip -c '%s' | tar xf -"), + ('tar.bz', "bunzip2 -c '%s' | tar xf -"), + ('tar.bz2', "bunzip2 -c '%s' | tar xf -"), + ('zip', "unzip '%s'"), + ('rar', "rar x '%s'"), + ('tar', "tar xf '%s'") + ) + + extract_stream = ( + # Compressed streams + ('gz', "gunzip -c -"), + ('bz', "bunzip2 -ck -"), + ('bz2', "bunzip2 -ck -") + ) + + def save_to_file(self, file): + command = self.op + if command.find('%s') != -1: + return pipe_through_command(command % file, + self.stream, None) + else: + return Saveable.save_to_file(self, file) + + def save_to_stream(self, stream): + command = self.op + if command.find('%s') != -1: + raise Exception('Sorry, archives can only be extracted into ' + 'a local directory.') + self.stream.seek(0) + pipe_through_command(command, self.stream, stream) + + def set_op(self, op): + self.op = op + +class DirData(saving.Saveable): + def __init__(self, source): + self.path = source + self.start = None + + create_arc = ( + ('tgz', "tar cf - '%s' | gzip"), + ('tar.gz', "tar cf - '%s' | gzip"), + ('tar.bz', "tar cf - '%s' | bzip2"), + ('tar.bz2', "tar cf - '%s' | bzip2"), + ('zip', "zip -r - '%s'"), + ('rar', "rar a - '%s'"), + ('tar', "tar cf - '%s'") + ) + + create_stream = () + extract_arc = () + extract_stream = () + + def save_to_stream(self, stream): + command = self.op % escape(self.path) + pipe_through_command(command, None, stream) + + def set_op(self, op): + self.op = op + +class ArchiveBox(saving.SaveBox): + def build_main_area(self): + self.vbox.add(self.save_area) + + self.operation = g.OptionMenu() + self.vbox.pack_start(self.operation, FALSE, TRUE, 0) + self.operation.show() + self.operation.set_border_width(5) + self.updating = 0 + + self.ops_menu = g.Menu() + self.operation.set_menu(self.ops_menu) + + def add_ops(self): + doc = self.save_area.document + self.i_to_op = [] + for op, command in doc.create_arc: + item = g.MenuItem('Create .%s archive' % op) + item.show() + self.ops_menu.append(item) + self.i_to_op.append(command) + for op, command in doc.create_stream: + item = g.MenuItem('Compress as .%s' % op) + item.show() + self.ops_menu.append(item) + self.i_to_op.append(command) + + if doc.start: + guess = formats.guess_format(doc.start) + else: + guess = None + + if guess in ['gz', 'bz2', 'bz']: + if doc.path.endswith('.tar.' + guess): + guess = 'tar.' + guess + + init = 0 + for op, command in doc.extract_arc: + item = g.MenuItem('Extract from a .%s' % op) + item.show() + self.ops_menu.append(item) + if op == guess: + init = len(self.i_to_op) + self.i_to_op.append(command) + for op, command in doc.extract_stream: + item = g.MenuItem('Uncompress .%s' % op) + item.show() + self.ops_menu.append(item) + if op == guess: + init = len(self.i_to_op) + self.i_to_op.append(command) + + name = doc.path + if name.endswith('.' + guess): + name = name[:-len(guess)-1] + self.save_area.entry.set_text(name) + + self.operation.connect('changed', self.op_changed) + self.save_area.entry.connect('changed', self.name_changed) + self.operation.set_history(init) + + def name_changed(self, entry): + if self.updating: + return + self.updating = 1 + + name = entry.get_text() + doc = self.save_area.document + i = 0 + for o, command in doc.create_arc + doc.create_stream: + if name.endswith('.' + o): + self.operation.set_history(i) + break + i += 1 + + self.updating = 0 + + def op_changed(self, operation): + if self.updating: + return + self.updating = 1 + + i = operation.get_history() + doc = self.save_area.document + doc.set_op(self.i_to_op[i]) + name = self.save_area.entry.get_text() + if not name: + name = doc.path + for o, command in doc.create_arc + doc.create_stream: + if name.endswith('.' + o): + name = name[:-len(o)-1] + break + if i < len(doc.create_arc): + name += '.' + doc.create_arc[i][0] + else: + i -= len(doc.create_arc) + if i < len(doc.create_stream): + name += '.' + doc.create_stream[i][0] + self.save_area.entry.set_text(name) + + self.updating = 0 + +# Check that our input is a regular local file. +# If not, fetch the data and put it in /tmp. + +path = sys.argv[1] + +source = None + +if path == '-': + source = sys.stdin +else: + path = rox.get_local_path(path) + if not path: + rox.croak('Sorry, I can only extract/archive local files.') + if not os.path.isdir(path): + try: + source = file(path) + except: + rox.report_exception() + sys.exit(1) + +if source: + data = FileData(path, source) +else: + data = DirData(path) + +savebox = ArchiveBox(data, '', 'text/plain') +savebox.show() +g.gdk.flush() + +savebox.add_ops() + +rox.mainloop() diff --git a/Archive.py b/Archive.py index e874dcc..2cd3c89 100644 --- a/Archive.py +++ b/Archive.py @@ -5,74 +5,12 @@ import os import signal import fcntl -from gtk import * -from GDK import * - -from rox.SaveBox import SaveBox -from rox import support -from rox import choices -import string +from rox.saving import SaveBox +from rox import g, choices child_pid = None -archive_formats = [ - # Extension, extract, create, type - ('.tar', "tar xf '%s'", "tar cf '%(dst)s' '%(src)s'", - 'application/x-tar'), - - ('.zip', "unzip '%s'", "zip -r '%(dst)s' '%(src)s'", - 'application/zip'), - - ('.deb', "ar x '%s'", None, 'application/x-deb'), - - ('.rar', "rar x '%s'", "rar a '%(dst)s' '%(src)s'", - 'application/x-rar'), - - ('.tgz', "gunzip -c '%s' | tar xf -", - "tar cf - '%(src)s' | gzip > '%(dst)s'", - 'application/x-compressed-tar'), - - ('.tar.gz', "gunzip -c '%s' | tar xf -", - "tar cf - '%(src)s' | gzip > '%(dst)s'", - 'application/x-compressed-tar'), - - ('.tbz', "bunzip2 -c '%s' | tar xf -", - "tar cf - '%(src)s' | bzip2 > '%(dst)s'", - 'application/x-bzip-compressed-tar'), - - ('.tar.bz', "bunzip2 -c '%s' | tar xf -", - "tar cf - '%(src)s' | bzip2 > '%(dst)s'", - 'application/x-bzip-compressed-tar'), - - ('.tbz2', "bunzip2 -c '%s' | tar xf -", - "tar cf - '%(src)s' | bzip2 > '%(dst)s'", - 'application/x-bzip-compressed-tar'), - - ('.tar.bz2', "bunzip2 -c '%s' | tar xf -", - "tar cf - '%(src)s' | bzip2 > '%(dst)s'", - 'application/x-bzip-compressed-tar'), - - ('.jar', "unzip '%s'", "zip -r '%(dst)s' '%(src)s'", - 'application/x-jar'), - - ('.rpm', "rpm2cpio '%s' | cpio -id --quiet", None, - 'application/x-rpm') - - ] - -compressed_formats = [ - # Ext, extract, compress, type - ('.gz', "gunzip -c '%s'", "gzip -c '%s'", 'application/x-gzip'), - ('.bz', "bunzip2 -ck '%s'", "bzip2 -c '%s'", 'application/x-bzip'), - ('.bz2', "bunzip2 -ck '%s'", "bzip2 -c '%s'", 'application/x-bzip') -] - -def get_format(path, formats): - for f in formats: - ext = f[0] - if ext == string.lower(path[-len(ext):]): - return f - return None +from formats import * def esc(text): """Return text with \ and ' escaped""" @@ -92,7 +30,7 @@ def bg_system(command, out = None): os.close(w) if out != None: os.close(out) - support.report_error("fork() failed!") + support.alert("fork() failed!") return 127 if child_pid == 0: # Child @@ -126,12 +64,12 @@ def bg_system(command, out = None): done[0] = done[0] + data else: done.append(1) - tag = input_add(r, INPUT_READ, cb) + tag = gtk.input_add_full(r, gtk.gdk.INPUT_READ, cb) while len(done) < 2: - mainiteration() + gtk.mainiteration() - input_remove(tag) + gtk.input_remove(tag) os.close(r) (pid, status) = os.waitpid(child_pid, 0) @@ -140,9 +78,9 @@ def bg_system(command, out = None): str = string.strip(done[0]) if status or str: if str: - support.report_error("Error: " + str) + support.alert(str) else: - support.report_error("Operation failed") + support.alert("Operation failed") return status @@ -163,8 +101,6 @@ def make_archiver(path): else: window = ArchiveFile(path) - window.connect('destroy', lambda w: support.rox_toplevel_unref()) - support.rox_toplevel_ref() window.show() def pull_up(dir): @@ -194,7 +130,7 @@ def report_known(formats): for f in formats: if f[2]: txt = txt + f[0] + '\n' - support.report_error(txt) + support.alert(txt) from os import _exit, fork, execvp, dup2 @@ -220,10 +156,7 @@ class Archive(SaveBox): if not hasattr(self, 'changed'): return - if hasattr(self, 'set_type'): - self.save_area.entry.connect('changed', self.changed) - else: - print "(a newer version of ROX-Lib would be nice)" + self.save_area.entry.connect('changed', self.changed) def destroyed(self, widget): global child_pid @@ -284,7 +217,7 @@ class ExtractFile(Archive): def do_save(self, path): if os.path.exists(path): - support.report_error("File `%s' already exists!" % path) + support.alert("File `%s' already exists!" % path) return FALSE stats = os.stat(self.path) mode = stat.S_IMODE(stats[stat.ST_MODE]) & 0x1ff; @@ -297,7 +230,7 @@ class ExtractFile(Archive): def cb(src, cond, self = self): self.data = self.data + os.read(src, 1024) - input_add(r, INPUT_READ, cb) + gtk.input_add_full(r, gtk.gdk.INPUT_READ, cb) bg_system(self.extract % esc(self.path), out = w) @@ -323,7 +256,7 @@ class ArchiveFile(Archive): return FALSE if os.path.exists(path): - support.report_error("File `%s' already exists!" % path) + support.alert("File `%s' already exists!" % path) return FALSE stats = os.stat(self.path) mode = stat.S_IMODE(stats[stat.ST_MODE]) & 0x1ff; diff --git a/findrox.py b/findrox.py index 411b2ac..31727d8 100644 --- a/findrox.py +++ b/findrox.py @@ -1,8 +1,8 @@ -# Most of the common code needed by ROX applications is in ROX-Lib. -# Except this code, which is needed to find ROX-Lib in the first place! +# Most of the common code needed by ROX applications is in ROX-Lib2. +# Except this code, which is needed to find ROX-Lib2 in the first place! # Just make sure you import findrox before importing anything inside -# ROX-Lib... +# ROX-Lib2... import os, sys from os.path import exists @@ -14,44 +14,46 @@ try: except KeyError: paths = [ os.environ['HOME'] + '/lib', '/usr/local/lib', '/usr/lib' ] -paths = map(lambda p: p +'/ROX-Lib', paths) -found = 0 +paths = map(lambda p: os.path.join(p, 'ROX-Lib2'), paths) for p in paths: if exists(p): - found = 1 - sys.path.append(p + '/python') + sys.path.append(os.path.join(p, 'python')) break -if not found: - err = "This program needs ROX-Lib to run.\n" + \ +else: + err = "This program needs ROX-Lib2 to run.\n" + \ "I tried all of these places:\n\n" + \ string.join(paths, '\n') + '\n\n' + \ - "ROX-Lib is available from:\nhttp://rox.sourceforge.net" + "ROX-Lib3 is available from:\nhttp://rox.sourceforge.net" try: sys.stderr.write('*** ' + err + '\n') except: pass - import gtk try: + import gtk2 as g + except: + import gtk win = gtk.GtkDialog() - message = gtk.GtkLabel(err) - except AttributeError: - win = gtk.MessageDialog(None, 0, - gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, err) + message = gtk.GtkLabel(err + + '\n\nAlso, pygtk2 needs to be present') + win.set_title('Missing ROX-Lib2') win.set_position(gtk.WIN_POS_CENTER) - win.run() - sys.exit(1) - win.set_title('Missing ROX-Lib') - win.set_position(gtk.WIN_POS_CENTER) - message.set_padding(20, 20) - win.vbox.pack_start(message) + message.set_padding(20, 20) + win.vbox.pack_start(message) - ok = gtk.GtkButton("OK") - ok.set_flags(gtk.CAN_DEFAULT) - win.action_area.pack_start(ok) - ok.connect('clicked', mainquit) - ok.grab_default() - - win.connect('destroy', mainquit) - win.show_all() - mainloop() + ok = gtk.GtkButton("OK") + ok.set_flags(gtk.CAN_DEFAULT) + win.action_area.pack_start(ok) + ok.connect('clicked', gtk.mainquit) + ok.grab_default() + + win.connect('destroy', gtk.mainquit) + win.show_all() + gtk.mainloop() + else: + box = g.MessageDialog(None, g.MESSAGE_ERROR, 0, + g.BUTTONS_OK, err) + box.set_title('Missing ROX-Lib2') + box.set_position(g.WIN_POS_CENTER) + box.set_default_response(g.RESPONSE_OK) + box.run() sys.exit(1) -- 2.11.4.GIT