1 # Copyright (C) 2008 Canonical Ltd
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 """Processor of import commands.
19 This module provides core processing functionality including an abstract class
20 for basing real processors on. See the processors package for examples.
27 from git_remote_helpers
.fastimport
import errors
29 log
= logging
.getLogger(__name__
)
32 class ImportProcessor(object):
33 """Base class for import processors.
35 Subclasses should override the pre_*, post_* and *_handler
36 methods as appropriate.
41 def __init__(self
, params
=None, verbose
=False, outf
=None):
43 self
.outf
= sys
.stdout
46 self
.verbose
= verbose
51 self
.validate_parameters()
53 # Handlers can set this to request exiting cleanly without
54 # iterating through the remaining commands
57 def validate_parameters(self
):
58 """Validate that the parameters are correctly specified."""
60 if p
not in self
.known_params
:
61 raise errors
.UnknownParameter(p
, self
.known_params
)
63 def process(self
, commands
):
64 """Process a stream of fast-import commands from a parser.
66 :param commands: a sequence of commands.ImportCommand objects
71 handler
= self
.__class
__.__dict
__[cmd
.name
+ "_handler"]
73 raise errors
.MissingHandler(cmd
.name
)
77 self
.post_handler(cmd
)
82 def pre_process(self
):
83 """Hook for logic at start of processing.
85 Called just before process() starts iterating over its sequence
90 def post_process(self
):
91 """Hook for logic at end of successful processing.
93 Called after process() finishes successfully iterating over its
94 sequence of commands (i.e. not called if an exception is raised
95 while processing commands).
99 def pre_handler(self
, cmd
):
100 """Hook for logic before each handler starts."""
103 def post_handler(self
, cmd
):
104 """Hook for logic after each handler finishes."""
107 def progress_handler(self
, cmd
):
108 """Process a ProgressCommand."""
109 raise NotImplementedError(self
.progress_handler
)
111 def blob_handler(self
, cmd
):
112 """Process a BlobCommand."""
113 raise NotImplementedError(self
.blob_handler
)
115 def checkpoint_handler(self
, cmd
):
116 """Process a CheckpointCommand."""
117 raise NotImplementedError(self
.checkpoint_handler
)
119 def commit_handler(self
, cmd
):
120 """Process a CommitCommand."""
121 raise NotImplementedError(self
.commit_handler
)
123 def reset_handler(self
, cmd
):
124 """Process a ResetCommand."""
125 raise NotImplementedError(self
.reset_handler
)
127 def tag_handler(self
, cmd
):
128 """Process a TagCommand."""
129 raise NotImplementedError(self
.tag_handler
)
131 def feature_handler(self
, cmd
):
132 """Process a FeatureCommand."""
133 raise NotImplementedError(self
.feature_handler
)
136 class CommitHandler(object):
137 """Base class for commit handling.
139 Subclasses should override the pre_*, post_* and *_handler
140 methods as appropriate.
143 def __init__(self
, command
):
144 self
.command
= command
147 self
.pre_process_files()
148 for fc
in self
.command
.file_cmds
:
150 handler
= self
.__class
__.__dict
__[fc
.name
[4:] + "_handler"]
152 raise errors
.MissingHandler(fc
.name
)
155 self
.post_process_files()
157 def _log(self
, level
, msg
, *args
):
158 log
.log(level
, msg
+ " (%s)", *(args
+ (self
.command
.id,)))
160 # Logging methods: unused in this library, but used by
161 # bzr-fastimport. Could be useful for other subclasses.
163 def note(self
, msg
, *args
):
164 """log.info() with context about the command"""
165 self
._log
(logging
.INFO
, msg
, *args
)
167 def warning(self
, msg
, *args
):
168 """log.warning() with context about the command"""
169 self
._log
(logging
.WARNING
, msg
, *args
)
171 def debug(self
, msg
, *args
):
172 """log.debug() with context about the command"""
173 self
._log
(logging
.DEBUG
, msg
, *args
)
175 def pre_process_files(self
):
176 """Prepare for committing."""
179 def post_process_files(self
):
180 """Save the revision."""
183 def modify_handler(self
, filecmd
):
184 """Handle a filemodify command."""
185 raise NotImplementedError(self
.modify_handler
)
187 def delete_handler(self
, filecmd
):
188 """Handle a filedelete command."""
189 raise NotImplementedError(self
.delete_handler
)
191 def copy_handler(self
, filecmd
):
192 """Handle a filecopy command."""
193 raise NotImplementedError(self
.copy_handler
)
195 def rename_handler(self
, filecmd
):
196 """Handle a filerename command."""
197 raise NotImplementedError(self
.rename_handler
)
199 def deleteall_handler(self
, filecmd
):
200 """Handle a filedeleteall command."""
201 raise NotImplementedError(self
.deleteall_handler
)
204 def parseMany(filenames
, parser_factory
, processor
):
205 """Parse multiple input files, sending the results all to
206 'processor'. parser_factory must be a callable that takes one input
207 file and returns an ImportParser instance, e.g. the ImportParser
208 class object itself. Each file in 'filenames' is opened, parsed,
209 and closed in turn. For filename \"-\", reads stdin.
211 for filename
in filenames
:
215 infile
= open(filename
, "rb")
218 parser
= parser_factory(infile
)
219 processor
.process(parser
.parse())