61 RECURSE_NOT_NOW = 3 |
61 RECURSE_NOT_NOW = 3 |
62 RECURSE_NEVER = 4 |
62 RECURSE_NEVER = 4 |
63 |
63 |
64 mimetypes.encodings_map.setdefault('.bz2', 'bzip2') |
64 mimetypes.encodings_map.setdefault('.bz2', 'bzip2') |
65 mimetypes.encodings_map.setdefault('.lzma', 'lzma') |
65 mimetypes.encodings_map.setdefault('.lzma', 'lzma') |
66 mimetypes.types_map.setdefault('.gem', 'x-ruby-gem') |
66 mimetypes.types_map.setdefault('.gem', 'application/x-ruby-gem') |
67 |
67 |
68 logger = logging.getLogger('dtrx-log') |
68 logger = logging.getLogger('dtrx-log') |
69 |
69 |
70 def run_command(command, description, stdout=None, stderr=None, stdin=None): |
70 def run_command(command, description, stdout=None, stderr=None, stdin=None): |
71 process = subprocess.Popen(command, stdin=stdin, stdout=stdout, |
71 process = subprocess.Popen(command, stdin=stdin, stdout=stdout, |
86 self.original_name = original_name |
86 self.original_name = original_name |
87 |
87 |
88 def is_free(self, filename): |
88 def is_free(self, filename): |
89 return not os.path.exists(filename) |
89 return not os.path.exists(filename) |
90 |
90 |
|
91 def create(self): |
|
92 fd, filename = tempfile.mkstemp(prefix=self.original_name + '.', |
|
93 dir='.') |
|
94 os.close(fd) |
|
95 return filename |
|
96 |
91 def check(self): |
97 def check(self): |
|
98 if self.is_free(self.original_name): |
|
99 return self.original_name |
92 for suffix in [''] + ['.%s' % (x,) for x in range(1, 10)]: |
100 for suffix in [''] + ['.%s' % (x,) for x in range(1, 10)]: |
93 filename = '%s%s' % (self.original_name, suffix) |
101 filename = '%s%s' % (self.original_name, suffix) |
94 if self.is_free(filename): |
102 if self.is_free(filename): |
95 return filename |
103 return filename |
96 raise ValueError("all alternatives for name %s taken" % |
104 return self.create() |
97 (self.original_name,)) |
105 |
98 |
|
99 |
106 |
100 class DirectoryChecker(FilenameChecker): |
107 class DirectoryChecker(FilenameChecker): |
101 def is_free(self, filename): |
108 def is_free(self, filename): |
102 try: |
109 try: |
103 os.mkdir(filename) |
110 os.mkdir(filename) |
104 except OSError, error: |
111 except OSError, error: |
105 if error.errno == errno.EEXIST: |
112 if error.errno == errno.EEXIST: |
106 return False |
113 return False |
107 raise |
114 raise |
108 return True |
115 return True |
|
116 |
|
117 def create(self): |
|
118 return tempfile.mkdtemp(prefix=self.original_name + '.', dir='.') |
109 |
119 |
110 |
120 |
111 class ExtractorError(Exception): |
121 class ExtractorError(Exception): |
112 pass |
122 pass |
113 |
123 |
139 |
149 |
140 def pipe(self, command, description="extraction"): |
150 def pipe(self, command, description="extraction"): |
141 self.pipes.append((command, description)) |
151 self.pipes.append((command, description)) |
142 |
152 |
143 def run_pipes(self, final_stdout=None): |
153 def run_pipes(self, final_stdout=None): |
144 if final_stdout is None: |
154 if not self.pipes: |
|
155 return |
|
156 elif final_stdout is None: |
145 # FIXME: Buffering this might be dumb. |
157 # FIXME: Buffering this might be dumb. |
146 final_stdout = tempfile.TemporaryFile() |
158 final_stdout = tempfile.TemporaryFile() |
147 if not self.pipes: |
|
148 return |
|
149 num_pipes = len(self.pipes) |
159 num_pipes = len(self.pipes) |
150 last_pipe = num_pipes - 1 |
160 last_pipe = num_pipes - 1 |
151 processes = [] |
161 processes = [] |
152 for index, command in enumerate([pipe[0] for pipe in self.pipes]): |
162 for index, command in enumerate([pipe[0] for pipe in self.pipes]): |
153 if index == 0: |
163 if index == 0: |
445 self.extractor.target]) |
455 self.extractor.target]) |
446 if status != 0: |
456 if status != 0: |
447 return "%s returned with exit status %s" % (command, status) |
457 return "%s returned with exit status %s" % (command, status) |
448 return self.organize() |
458 return self.organize() |
449 |
459 |
|
460 def set_target(self, target, checker): |
|
461 self.target = checker(target).check() |
|
462 if self.target != target: |
|
463 logger.warning("extracting %s to %s" % |
|
464 (self.extractor.filename, self.target)) |
|
465 |
450 |
466 |
451 # The "where to extract" table, with options and archive types. |
467 # The "where to extract" table, with options and archive types. |
452 # This dictates the contents of each can_handle method. |
468 # This dictates the contents of each can_handle method. |
453 # |
469 # |
454 # Flat Overwrite None |
470 # Flat Overwrite None |
511 checker = FilenameChecker |
527 checker = FilenameChecker |
512 if self.options.one_entry_policy == EXTRACT_HERE: |
528 if self.options.one_entry_policy == EXTRACT_HERE: |
513 destination = self.extractor.content_name.rstrip('/') |
529 destination = self.extractor.content_name.rstrip('/') |
514 else: |
530 else: |
515 destination = self.extractor.basename() |
531 destination = self.extractor.basename() |
516 self.target = checker(destination).check() |
532 self.set_target(destination, checker) |
517 if os.path.isdir(self.extractor.target): |
533 if os.path.isdir(self.extractor.target): |
518 os.rename(source, self.target) |
534 os.rename(source, self.target) |
519 os.rmdir(self.extractor.target) |
535 os.rmdir(self.extractor.target) |
520 else: |
536 else: |
521 os.rename(self.extractor.target, self.target) |
537 os.rename(self.extractor.target, self.target) |
535 return True |
551 return True |
536 can_handle = staticmethod(can_handle) |
552 can_handle = staticmethod(can_handle) |
537 |
553 |
538 def organize(self): |
554 def organize(self): |
539 basename = self.extractor.basename() |
555 basename = self.extractor.basename() |
540 self.target = self.extractor.name_checker(basename).check() |
556 self.set_target(basename, self.extractor.name_checker) |
541 os.rename(self.extractor.target, self.target) |
557 os.rename(self.extractor.target, self.target) |
542 |
558 |
543 |
559 |
544 class BasePolicy(object): |
560 class BasePolicy(object): |
545 def __init__(self, options): |
561 def __init__(self, options): |