Exemple #1
0
 def __setstate__(self, state):
     (
         cvs_file_id,
         cvs_items,
         original_ids,
     ) = state
     cvs_file = Ctx()._cvs_path_db.get_path(cvs_file_id)
     CVSFileItems.__init__(
         self,
         cvs_file,
         cvs_file.project.get_trunk(),
         cvs_items,
         original_ids=original_ids,
     )
Exemple #2
0
    def _get_metadata(self):
        """Return the Metadata instance for this commit."""

        if self._metadata is None:
            # Set self._metadata for this commit from that of the first cvs
            # revision.
            if not self.cvs_revs:
                raise InternalError(
                    'SVNPrimaryCommit contains no CVS revisions')

            metadata_id = self.cvs_revs[0].metadata_id
            self._metadata = Ctx()._metadata_db[metadata_id]

        return self._metadata
Exemple #3
0
def prime_ctx():
    def rf(filename):
        artifact_manager.register_temp_file(filename, None)

    from cvs2svn_lib.common import DB_OPEN_READ
    from cvs2svn_lib.symbol_database import SymbolDatabase
    from cvs2svn_lib.cvs_path_database import CVSPathDatabase
    rf(config.CVS_PATHS_DB)
    rf(config.SYMBOL_DB)
    from cvs2svn_lib.cvs_item_database import OldCVSItemStore
    from cvs2svn_lib.metadata_database import MetadataDatabase
    rf(config.METADATA_DB)
    rf(config.CVS_ITEMS_STORE)
    rf(config.CVS_ITEMS_FILTERED_STORE)
    rf(config.CVS_ITEMS_FILTERED_INDEX_TABLE)
    artifact_manager.pass_started(None)

    Ctx()._projects = ProjectList()
    Ctx()._symbol_db = SymbolDatabase()
    Ctx()._cvs_path_db = CVSPathDatabase(DB_OPEN_READ)
    Ctx()._cvs_items_db = OldCVSItemStore(
        artifact_manager.get_temp_file(config.CVS_ITEMS_STORE))
    Ctx()._metadata_db = MetadataDatabase(DB_OPEN_READ)
Exemple #4
0
def main(progname, run_options, pass_manager):
    # Convenience var, so we don't have to keep instantiating this Borg.
    ctx = Ctx()

    # Make sure the tmp directory exists.  Note that we don't check if
    # it's empty -- we want to be able to use, for example, "." to hold
    # tempfiles.
    if ctx.tmpdir is None:
        ctx.tmpdir = tempfile.mkdtemp(prefix=('%s-' % (progname, )))
        erase_tmpdir = True
        logger.quiet(
            'Writing temporary files to %r\n'
            'Be sure to use --tmpdir=%r if you need to resume this conversion.'
            % (
                ctx.tmpdir,
                ctx.tmpdir,
            ), )
    elif not os.path.exists(ctx.tmpdir):
        os.mkdir(ctx.tmpdir)
        erase_tmpdir = True
    elif not os.path.isdir(ctx.tmpdir):
        raise FatalError(
            "cvs2svn tried to use '%s' for temporary files, but that path\n"
            "  exists and is not a directory.  Please make it be a directory,\n"
            "  or specify some other directory for temporary files." %
            (ctx.tmpdir, ))
    else:
        erase_tmpdir = False

    # But do lock the tmpdir, to avoid process clash.
    try:
        os.mkdir(os.path.join(ctx.tmpdir, 'cvs2svn.lock'))
    except OSError, e:
        if e.errno == errno.EACCES:
            raise FatalError("Permission denied:" +
                             " No write access to directory '%s'." %
                             ctx.tmpdir)
        if e.errno == errno.EEXIST:
            raise FatalError(
                "cvs2svn is using directory '%s' for temporary files, but\n"
                "  subdirectory '%s/cvs2svn.lock' exists, indicating that another\n"
                "  cvs2svn process is currently using '%s' as its temporary\n"
                "  workspace.  If you are certain that is not the case,\n"
                "  then remove the '%s/cvs2svn.lock' subdirectory." % (
                    ctx.tmpdir,
                    ctx.tmpdir,
                    ctx.tmpdir,
                    ctx.tmpdir,
                ))
        raise
Exemple #5
0
def main(progname, cmd_args):
    # Disable garbage collection, as we try not to create any circular
    # data structures:
    gc.disable()

    # Convenience var, so we don't have to keep instantiating this Borg.
    ctx = Ctx()

    pass_manager = PassManager(passes)

    run_options = RunOptions(progname, cmd_args, pass_manager)

    # Make sure the tmp directory exists.  Note that we don't check if
    # it's empty -- we want to be able to use, for example, "." to hold
    # tempfiles.  But if we *did* want check if it were empty, we'd do
    # something like os.stat(ctx.tmpdir)[stat.ST_NLINK], of course :-).
    if not os.path.exists(ctx.tmpdir):
        erase_tmpdir = True
        os.mkdir(ctx.tmpdir)
    elif not os.path.isdir(ctx.tmpdir):
        raise FatalError(
            "cvs2svn tried to use '%s' for temporary files, but that path\n"
            "  exists and is not a directory.  Please make it be a directory,\n"
            "  or specify some other directory for temporary files." %
            (ctx.tmpdir, ))
    else:
        erase_tmpdir = False

    # But do lock the tmpdir, to avoid process clash.
    try:
        os.mkdir(os.path.join(ctx.tmpdir, 'cvs2svn.lock'))
    except OSError, e:
        if e.errno == errno.EACCES:
            raise FatalError("Permission denied:" +
                             " No write access to directory '%s'." %
                             ctx.tmpdir)
        if e.errno == errno.EEXIST:
            raise FatalError(
                "cvs2svn is using directory '%s' for temporary files, but\n"
                "  subdirectory '%s/cvs2svn.lock' exists, indicating that another\n"
                "  cvs2svn process is currently using '%s' as its temporary\n"
                "  workspace.  If you are certain that is not the case,\n"
                "  then remove the '%s/cvs2svn.lock' subdirectory." % (
                    ctx.tmpdir,
                    ctx.tmpdir,
                    ctx.tmpdir,
                    ctx.tmpdir,
                ))
        raise
Exemple #6
0
    def _utf8_path(self, path):
        """Return a copy of PATH encoded in UTF-8."""

        # Convert each path component separately (as they may each use
        # different encodings).
        try:
            return '/'.join([
                Ctx().cvs_filename_decoder(piece).encode('utf8')
                for piece in path.split('/')
            ])
        except UnicodeError:
            raise FatalError(
                "Unable to convert a path '%s' to internal encoding.\n"
                "Consider rerunning with one or more '--encoding' parameters or\n"
                "with '--fallback-encoding'." % (path, ))
Exemple #7
0
    def __init__(self, revision_reader, target):
        self.target = target

        # Since the output of this run is a repository, not a dumpfile,
        # the temporary dumpfiles we create should go in the tmpdir.  But
        # since we delete it ourselves, we don't want to use
        # artifact_manager.
        DumpfileDelegate.__init__(self, revision_reader,
                                  Ctx().get_temp_filename(DUMPFILE))

        self.dumpfile = open(self.dumpfile_path, 'w+b')
        self.loader_pipe = subprocess.Popen(
            [Ctx().svnadmin_executable, 'load', '-q', self.target],
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
        )
        self.loader_pipe.stdout.close()
        try:
            self._write_dumpfile_header(self.loader_pipe.stdin)
        except IOError:
            raise FatalError('svnadmin failed with the following output while '
                             'loading the dumpfile:\n%s' %
                             (self.loader_pipe.stderr.read(), ))
  def store(self, project, branch_name, author, log_msg):
    """Store the metadata and return its id.

    Locate the record for a commit with the specified (PROJECT,
    BRANCH_NAME, AUTHOR, LOG_MSG) and return its id.  (Depending on
    policy, not all of these items are necessarily used when creating
    the unique id.)  If there is no such record, create one and return
    its newly-generated id."""

    key = [author, log_msg]
    if not Ctx().cross_project_commits:
      key.append('%x' % project.id)
    if not Ctx().cross_branch_commits:
      key.append(branch_name or '')

    digest = sha.new('\0'.join(key)).digest()
    try:
      # See if it is already known:
      return self._digest_to_id[digest]
    except KeyError:
      id = self.key_generator.gen_id()
      self._digest_to_id[digest] = id
      self._metadata_db[id] = Metadata(id, author, log_msg)
      return id
Exemple #9
0
  def _adjust_branch_parents(self, cvs_branch):
    """Adjust the parent of CVS_BRANCH if possible and preferred.

    CVS_BRANCH is an instance of CVSBranch.  This method must be
    called in leaf-to-trunk order."""

    # The Symbol that cvs_branch would like to have as a parent:
    preferred_parent = Ctx()._symbol_db.get_symbol(
        cvs_branch.symbol.preferred_parent_id)

    if cvs_branch.source_lod == preferred_parent:
      # The preferred parent is already the parent.
      return

    # The CVSRevision that is its direct parent:
    source = self[cvs_branch.source_id]
    # This is always a CVSRevision because we haven't adjusted it yet:
    assert isinstance(source, CVSRevision)

    if isinstance(preferred_parent, Trunk):
      # It is not possible to graft *onto* Trunk:
      return

    # Try to find the preferred parent among the possible parents:
    for branch_id in source.branch_ids:
      possible_parent = self[branch_id]
      if possible_parent.symbol == preferred_parent:
        # We found it!
        break
      elif possible_parent.symbol == cvs_branch.symbol:
        # Only branches that precede the branch to be adjusted are
        # considered possible parents.  Leave parentage unchanged:
        return
    else:
      # This point should never be reached.
      raise InternalError(
          'Possible parent search did not terminate as expected')

    parent = possible_parent
    assert isinstance(parent, CVSBranch)

    logger.debug('Grafting %s from %s (on %s) onto %s' % (
                cvs_branch, source, source.lod, parent,))
    # Switch parent:
    source.branch_ids.remove(cvs_branch.id)
    parent.branch_ids.append(cvs_branch.id)
    cvs_branch.source_lod = parent.symbol
    cvs_branch.source_id = parent.id
Exemple #10
0
    def _process_revision_changeset(self, changeset, timestamp):
        """Process CHANGESET, using TIMESTAMP as the commit time.

    Create and yield one or more SVNCommits in the process.  CHANGESET
    must be an OrderedChangeset.  TIMESTAMP is used as the timestamp
    for any resulting SVNCommits."""

        if not changeset.cvs_item_ids:
            logger.warn('Changeset has no items: %r' % changeset)
            return

        logger.verbose('-' * 60)
        logger.verbose('CVS Revision grouping:')
        logger.verbose('  Time: %s' % time.ctime(timestamp))

        # Generate an SVNCommit unconditionally.  Even if the only change in
        # this group of CVSRevisions is a deletion of an already-deleted
        # file (that is, a CVS revision in state 'dead' whose predecessor
        # was also in state 'dead'), the conversion will still generate a
        # Subversion revision containing the log message for the second dead
        # revision, because we don't want to lose that information.

        cvs_revs = list(changeset.iter_cvs_items())
        if cvs_revs:
            cvs_revs.sort(
                lambda a, b: cmp(a.cvs_file.rcs_path, b.cvs_file.rcs_path))
            svn_commit = SVNPrimaryCommit(cvs_revs, timestamp,
                                          self.revnum_generator.gen_id())

            yield svn_commit

            for cvs_rev in cvs_revs:
                Ctx()._symbolings_logger.log_revision(cvs_rev,
                                                      svn_commit.revnum)

            # Generate an SVNPostCommit if we have default branch revs.  If
            # some of the revisions in this commit happened on a non-trunk
            # default branch, then those files have to be copied into trunk
            # manually after being changed on the branch (because the RCS
            # "default branch" appears as head, i.e., trunk, in practice).
            # Unfortunately, Subversion doesn't support copies with sources
            # in the current txn.  All copies must be based in committed
            # revisions.  Therefore, we generate the copies in a new
            # revision.
            for svn_post_commit in self._post_commit(cvs_revs,
                                                     svn_commit.revnum,
                                                     timestamp):
                yield svn_post_commit
Exemple #11
0
    def _adjust_tag_parent(self, cvs_tag):
        """Adjust the parent of CVS_TAG if possible and preferred.

    CVS_TAG is an instance of CVSTag.  This method must be called in
    leaf-to-trunk order."""

        # The Symbol that cvs_tag would like to have as a parent:
        preferred_parent = Ctx()._symbol_db.get_symbol(
            cvs_tag.symbol.preferred_parent_id)

        if cvs_tag.source_lod == preferred_parent:
            # The preferred parent is already the parent.
            return

        # The CVSRevision that is its direct parent:
        source = self[cvs_tag.source_id]
        assert isinstance(source, CVSRevision)

        if isinstance(preferred_parent, Trunk):
            # It is not possible to graft *onto* Trunk:
            return

        # Try to find the preferred parent among the possible parents:
        for branch_id in source.branch_ids:
            if self[branch_id].symbol == preferred_parent:
                # We found it!
                break
        else:
            # The preferred parent is not a possible parent in this file.
            return

        parent = self[branch_id]
        assert isinstance(parent, CVSBranch)

        Log().debug('Grafting %s from %s (on %s) onto %s' % (
            cvs_tag,
            source,
            source.lod,
            parent,
        ))
        # Switch parent:
        source.tag_ids.remove(cvs_tag.id)
        parent.tag_ids.append(cvs_tag.id)
        cvs_tag.source_lod = parent.symbol
        cvs_tag.source_id = parent.id
    def process_output_options(self):
        """Process the options related to SVN output."""

        ctx = Ctx()
        options = self.options

        if options.dump_only and not options.dumpfile:
            raise FatalError(
                "'--dump-only' requires '--dumpfile' to be specified.")

        if not options.svnrepos and not options.dumpfile and not ctx.dry_run:
            raise FatalError("must pass one of '-s' or '--dumpfile'.")

        not_both(options.svnrepos, '-s', options.dumpfile, '--dumpfile')

        not_both(options.dumpfile, '--dumpfile', options.existing_svnrepos,
                 '--existing-svnrepos')

        not_both(options.bdb_txn_nosync, '--bdb-txn-nosync',
                 options.existing_svnrepos, '--existing-svnrepos')

        not_both(options.dumpfile, '--dumpfile', options.bdb_txn_nosync,
                 '--bdb-txn-nosync')

        not_both(options.fs_type, '--fs-type', options.existing_svnrepos,
                 '--existing-svnrepos')

        if (options.fs_type and options.fs_type != 'bdb'
                and options.bdb_txn_nosync):
            raise FatalError(
                "cannot pass --bdb-txn-nosync with --fs-type=%s." %
                options.fs_type)

        if options.svnrepos:
            if options.existing_svnrepos:
                ctx.output_option = ExistingRepositoryOutputOption(
                    options.svnrepos)
            else:
                ctx.output_option = NewRepositoryOutputOption(
                    options.svnrepos,
                    fs_type=options.fs_type,
                    bdb_txn_nosync=options.bdb_txn_nosync,
                    create_options=options.create_options)
        else:
            ctx.output_option = DumpfileOutputOption(options.dumpfile)
Exemple #13
0
def get_source_set(symbol, range_map):
    """Return a FillSource describing the fill sources for RANGE_MAP.

  SYMBOL is either a Branch or a Tag.  RANGE_MAP is a map { CVSSymbol
  : SVNRevisionRange } as returned by
  SymbolingsReader.get_range_map().

  Use the SVNRevisionRanges from RANGE_MAP to create a FillSource
  instance describing the sources for filling SYMBOL."""

    root_cvs_directory = Ctx()._cvs_file_db.get_file(
        symbol.project.root_cvs_directory_id)
    fill_source = FillSource(root_cvs_directory, symbol, {})

    for cvs_symbol, svn_revision_range in range_map.items():
        fill_source._set_node(cvs_symbol.cvs_file, svn_revision_range)

    return fill_source
    def __init__(self, cvs_rev, svn_props_changed):
        """Initialize instance and record the properties for this file.
    SVN_PROPS_CHANGED indicates whether the svn: properties are known
    to have changed since the last revision.

    The properties are set by the SVNPropertySetters in
    Ctx().svn_property_setters."""

        self.cvs_rev = cvs_rev
        # Did the svn properties change for this file (i.e., do they have
        # to be written to the dumpfile?)
        self.svn_props_changed = svn_props_changed

        # The properties for this item as a map { key : value }.  If VALUE
        # is None, the property should be left unset.
        self.svn_props = {}

        for svn_property_setter in Ctx().svn_property_setters:
            svn_property_setter.set_properties(self)
Exemple #15
0
    def _process_cvs_file_items(self, cvs_file_items):
        """Process the CVSFileItems from one CVSFile."""

        # Remove an initial delete on trunk if it is not needed:
        cvs_file_items.remove_unneeded_initial_trunk_delete(self.metadata_db)

        # Remove initial branch deletes that are not needed:
        cvs_file_items.remove_initial_branch_deletes(self.metadata_db)

        # If this is a --trunk-only conversion, discard all branches and
        # tags, then draft any non-trunk default branch revisions to
        # trunk:
        if Ctx().trunk_only:
            cvs_file_items.exclude_non_trunk()

        cvs_file_items.check_link_consistency()

        self.add_cvs_file_items(cvs_file_items)
        self.symbol_stats.register(cvs_file_items)
Exemple #16
0
  def _process_cvs_file_items(self, cvs_file_items):
    """Process the CVSFileItems from one CVSFile."""

    # Remove CVSRevisionDeletes that are not needed:
    cvs_file_items.remove_unneeded_deletes(self.collect_data.metadata_db)

    # Remove initial branch deletes that are not needed:
    cvs_file_items.remove_initial_branch_deletes(
        self.collect_data.metadata_db
        )

    # If this is a --trunk-only conversion, discard all branches and
    # tags, then draft any non-trunk default branch revisions to
    # trunk:
    if Ctx().trunk_only:
      cvs_file_items.exclude_non_trunk()

    self.collect_data.revision_recorder.finish_file(cvs_file_items)
    self.collect_data.add_cvs_file_items(cvs_file_items)
    self.collect_data.symbol_stats.register(cvs_file_items)
Exemple #17
0
  def check_options(self):
    """Check the the run options are OK.

    This should only be called after all options have been processed."""

    # Convenience var, so we don't have to keep instantiating this Borg.
    ctx = Ctx()

    if not self.start_pass <= self.end_pass:
      raise InvalidPassError(
          'Ending pass must not come before starting pass.')

    if not ctx.dry_run and ctx.output_option is None:
      raise FatalError('No output option specified.')

    if ctx.output_option is not None:
      ctx.output_option.check()

    if not self.projects:
      raise FatalError('No project specified.')
Exemple #18
0
    def process_symbol_strategy_options(self):
        """Process symbol strategy-related options."""

        ctx = Ctx()
        options = self.options

        # Add the standard symbol name cleanup rules:
        self.options.symbol_transforms.extend([
            ReplaceSubstringsSymbolTransform('\\', '/'),
            # Remove leading, trailing, and repeated slashes:
            NormalizePathsSymbolTransform(),
        ])

        if ctx.trunk_only:
            if options.symbol_strategy_rules or options.keep_trivial_imports:
                raise SymbolOptionsWithTrunkOnlyException()

        else:
            if not options.keep_trivial_imports:
                options.symbol_strategy_rules.append(
                    ExcludeTrivialImportBranchRule())

            options.symbol_strategy_rules.append(UnambiguousUsageRule())
            if options.symbol_default == 'strict':
                pass
            elif options.symbol_default == 'branch':
                options.symbol_strategy_rules.append(AllBranchRule())
            elif options.symbol_default == 'tag':
                options.symbol_strategy_rules.append(AllTagRule())
            elif options.symbol_default == 'heuristic':
                options.symbol_strategy_rules.append(BranchIfCommitsRule())
                options.symbol_strategy_rules.append(HeuristicStrategyRule())
            elif options.symbol_default == 'exclude':
                options.symbol_strategy_rules.append(AllExcludedRule())
            else:
                assert False

            # Now add a rule whose job it is to pick the preferred parents of
            # branches and tags:
            options.symbol_strategy_rules.append(
                HeuristicPreferredParentRule())
Exemple #19
0
def generate_ignores(cvsignore, raw_ignore_val):
    ignore_vals = []
    for ignore in raw_ignore_val.split():
        # Reset the list if we encounter a '!'
        # See http://cvsbook.red-bean.com/cvsbook.html#cvsignore
        if ignore == '!':
            ignore_vals = []
        else:
            try:
                ignore = Ctx().cvs_filename_decoder.decode_path(ignore).encode(
                    'utf8')
            except UnicodeError:
                raise FatalError(
                    "Unable to convert path '%s' (found in file %s) to internal encoding.\n"
                    "Consider rerunning with one or more '--encoding' parameters or\n"
                    "with '--fallback-encoding'." % (
                        ignore,
                        cvsignore,
                    ))
            ignore_vals.append(ignore)
    return ignore_vals
Exemple #20
0
    def process_io_options(self):
        """Process input/output options.

    Process options related to extracting data from the CVS repository
    and writing to 'git fast-import'-formatted files."""

        ctx = Ctx()
        options = self.options

        not_both(options.use_rcs, '--use-rcs', options.use_cvs, '--use-cvs')

        if options.use_rcs:
            revision_reader = RCSRevisionReader(
                co_executable=options.co_executable)
        else:
            # --use-cvs is the default:
            revision_reader = CVSRevisionReader(
                cvs_executable=options.cvs_executable)

        if ctx.dry_run:
            ctx.revision_recorder = NullRevisionRecorder()
        else:
            if not (options.blobfile and options.dumpfile):
                raise FatalError(
                    "must pass '--blobfile' and '--dumpfile' options.")
            ctx.revision_recorder = SimpleFulltextRevisionRecorderAdapter(
                revision_reader,
                GitRevisionRecorder(options.blobfile),
            )

        ctx.revision_excluder = NullRevisionExcluder()
        ctx.revision_reader = None

        ctx.output_option = GitOutputOption(
            options.dumpfile,
            GitRevisionMarkWriter(),
            max_merges=None,
            # Optional map from CVS author names to git author names:
            author_transforms={},  # FIXME
        )
Exemple #21
0
    def process_all_extraction_options(self):
        ctx = Ctx()
        options = self.options

        not_both(options.use_rcs, '--use-rcs', options.use_cvs, '--use-cvs')

        not_both(options.use_rcs, '--use-rcs', options.use_internal_co,
                 '--use-internal-co')

        not_both(options.use_cvs, '--use-cvs', options.use_internal_co,
                 '--use-internal-co')

        if options.use_rcs:
            ctx.revision_collector = NullRevisionCollector()
            ctx.revision_reader = RCSRevisionReader(options.co_executable)
        elif options.use_cvs:
            ctx.revision_collector = NullRevisionCollector()
            ctx.revision_reader = CVSRevisionReader(options.cvs_executable)
        else:
            # --use-internal-co is the default:
            ctx.revision_collector = InternalRevisionCollector(compress=True)
            ctx.revision_reader = InternalRevisionReader(compress=True)
Exemple #22
0
    def _get_cvs_file(
        self,
        parent_directory,
        basename,
        file_in_attic=False,
        leave_in_attic=False,
    ):
        """Return a CVSFile describing the file with name BASENAME.

    PARENT_DIRECTORY is the CVSDirectory instance describing the
    directory that physically holds this file in the filesystem.
    BASENAME must be the base name of a *,v file within
    PARENT_DIRECTORY.

    FILE_IN_ATTIC is a boolean telling whether the specified file is
    in an Attic subdirectory.  If FILE_IN_ATTIC is True, then:

    - If LEAVE_IN_ATTIC is True, then leave the 'Attic' component in
      the filename.

    - Otherwise, raise FileInAndOutOfAtticException if a file with the
      same filename appears outside of Attic.

    The CVSFile is assigned a new unique id.  All of the CVSFile
    information is filled in except mode (which can only be determined
    by parsing the file).

    Raise FatalError if the resulting filename would not be legal in
    SVN."""

        filename = os.path.join(parent_directory.rcs_path, basename)
        try:
            Ctx().output_option.verify_filename_legal(basename[:-2])
        except IllegalSVNPathError, e:
            raise FatalError(
                'File %r would result in an illegal SVN filename: %s' % (
                    filename,
                    e,
                ))
Exemple #23
0
  def _modify_file(self, cvs_item, post_commit):
    if cvs_item.cvs_file.executable:
      mode = '100755'
    else:
      mode = '100644'

    self.f.write(
        'M %s inline %s\n'
        % (mode, cvs_item.cvs_file.cvs_path,)
        )

    if isinstance(cvs_item, CVSSymbol):
      cvs_rev = cvs_item.get_cvs_revision_source(Ctx()._cvs_items_db)
    else:
      cvs_rev = cvs_item

    # FIXME: We have to decide what to do about keyword substitution
    # and eol_style here:
    fulltext = self.revision_reader.get_content(cvs_rev)

    self.f.write('data %d\n' % (len(fulltext),))
    self.f.write(fulltext)
    self.f.write('\n')
    def process_extraction_options(self):
        """Process options related to extracting data from the CVS repository."""

        ctx = Ctx()
        options = self.options

        not_both(options.use_rcs, '--use-rcs', options.use_cvs, '--use-cvs')
        not_both(options.use_external_blob_generator,
                 '--use-external-blob-generator', options.use_cvs, '--use-cvs')
        not_both(options.use_external_blob_generator,
                 '--use-external-blob-generator', options.use_rcs, '--use-rcs')

        # cvs2git never needs a revision reader:
        ctx.revision_reader = None

        if ctx.dry_run:
            ctx.revision_collector = NullRevisionCollector()
            return

        if not (options.blobfile and options.dumpfile):
            raise FatalError(
                "must pass '--blobfile' and '--dumpfile' options.")

        if options.use_external_blob_generator:
            ctx.revision_collector = ExternalBlobGenerator(options.blobfile)
        else:
            if options.use_rcs:
                revision_reader = RCSRevisionReader(
                    co_executable=options.co_executable)
            else:
                # --use-cvs is the default:
                revision_reader = CVSRevisionReader(
                    cvs_executable=options.cvs_executable)
            ctx.revision_collector = GitRevisionCollector(
                options.blobfile,
                revision_reader,
            )
Exemple #25
0
    def copy_path(self, cvs_path, src_lod, dest_lod, src_revnum):
        if isinstance(cvs_path, CVSFile):
            node_kind = 'file'
            if cvs_path.rcs_basename == '.cvsignore':
                # FIXME: Here we have to adjust the containing directory's
                # svn:ignore property to reflect the addition of the
                # .cvsignore file to the LOD!  This is awkward because we
                # don't have the contents of the .cvsignore file available.
                if not Ctx().keep_cvsignore:
                    return
        elif isinstance(cvs_path, CVSDirectory):
            node_kind = 'dir'
        else:
            raise InternalError()

        self._dumpfile.write(
            'Node-path: %s\n'
            'Node-kind: %s\n'
            'Node-action: add\n'
            'Node-copyfrom-rev: %d\n'
            'Node-copyfrom-path: %s\n'
            '\n' %
            (utf8_path(dest_lod.get_path(cvs_path.cvs_path)), node_kind,
             src_revnum, utf8_path(src_lod.get_path(cvs_path.cvs_path))))
Exemple #26
0
    def delete_path(self, lod, cvs_path):
        dir_path, basename = path_split(lod.get_path(cvs_path.get_cvs_path()))
        if basename == '.cvsignore':
            # When a .cvsignore file is deleted, the directory's svn:ignore
            # property needs to be deleted.
            ignore_contents = 'PROPS-END\n'
            ignore_len = len(ignore_contents)

            # write headers, then props
            self._dumpfile.write('Node-path: %s\n'
                                 'Node-kind: dir\n'
                                 'Node-action: change\n'
                                 'Prop-content-length: %d\n'
                                 'Content-length: %d\n'
                                 '\n'
                                 '%s' % (self._utf8_path(dir_path), ignore_len,
                                         ignore_len, ignore_contents))
            if not Ctx().keep_cvsignore:
                return

        self._dumpfile.write(
            'Node-path: %s\n'
            'Node-action: delete\n'
            '\n' % (self._utf8_path(lod.get_path(cvs_path.cvs_path)), ))
Exemple #27
0
    def _process_tag_changeset(self, changeset, timestamp):
        """Process TagChangeset CHANGESET, producing a SVNTagCommit.

    Filter out CVSTagNoops.  If no CVSTags are left, don't generate a
    SVNTagCommit."""

        if Ctx().trunk_only:
            raise InternalError(
                'TagChangeset encountered during a --trunk-only conversion')

        cvs_tag_ids = [
            cvs_tag.id for cvs_tag in changeset.iter_cvs_items()
            if not isinstance(cvs_tag, CVSTagNoop)
        ]
        if cvs_tag_ids:
            yield SVNTagCommit(
                changeset.symbol,
                cvs_tag_ids,
                timestamp,
                self.revnum_generator.gen_id(),
            )
        else:
            logger.debug('Omitting %r because it contains only CVSTagNoops' %
                         (changeset, ))
Exemple #28
0
    def process_changeset(self, changeset, timestamp):
        """Process CHANGESET, using TIMESTAMP for all of its entries.

    Return a generator that generates the resulting SVNCommits.

    The changesets must be fed to this function in proper dependency
    order."""

        # First create any new projects that might be opened by the
        # changeset:
        projects_opened = \
            changeset.get_projects_opened() - self._initialized_projects
        if projects_opened:
            if Ctx().cross_project_commits:
                yield SVNInitialProjectCommit(timestamp, projects_opened,
                                              self.revnum_generator.gen_id())
            else:
                for project in projects_opened:
                    yield SVNInitialProjectCommit(
                        timestamp, [project], self.revnum_generator.gen_id())
            self._initialized_projects.update(projects_opened)

        if isinstance(changeset, OrderedChangeset):
            for svn_commit \
                    in self._process_revision_changeset(changeset, timestamp):
                yield svn_commit
        elif isinstance(changeset, TagChangeset):
            for svn_commit in self._process_tag_changeset(
                    changeset, timestamp):
                yield svn_commit
        elif isinstance(changeset, BranchChangeset):
            for svn_commit in self._process_branch_changeset(
                    changeset, timestamp):
                yield svn_commit
        else:
            raise TypeError('Illegal changeset %r' % changeset)
Exemple #29
0
class InternalRevisionReader(RevisionReader):
    """A RevisionReader that reads the contents from an own delta store."""
    def __init__(self, compress):
        # Only import Database if an InternalRevisionReader is really
        # instantiated, because the import fails if a decent dbm is not
        # installed.
        from cvs2svn_lib.database import Database
        self._Database = Database

        self._compress = compress

    def register_artifacts(self, which_pass):
        artifact_manager.register_temp_file(config.CVS_CHECKOUT_DB, which_pass)
        artifact_manager.register_temp_file_needed(config.RCS_DELTAS_STORE,
                                                   which_pass)
        artifact_manager.register_temp_file_needed(
            config.RCS_DELTAS_INDEX_TABLE, which_pass)
        artifact_manager.register_temp_file_needed(config.RCS_TREES_STORE,
                                                   which_pass)
        artifact_manager.register_temp_file_needed(
            config.RCS_TREES_INDEX_TABLE, which_pass)

    def start(self):
        self._delta_db = IndexedDatabase(
            artifact_manager.get_temp_file(config.RCS_DELTAS_STORE),
            artifact_manager.get_temp_file(config.RCS_DELTAS_INDEX_TABLE),
            DB_OPEN_READ,
        )
        self._delta_db.__delitem__ = lambda id: None
        self._tree_db = IndexedDatabase(
            artifact_manager.get_temp_file(config.RCS_TREES_STORE),
            artifact_manager.get_temp_file(config.RCS_TREES_INDEX_TABLE),
            DB_OPEN_READ,
        )
        serializer = MarshalSerializer()
        if self._compress:
            serializer = CompressingSerializer(serializer)
        self._co_db = self._Database(
            artifact_manager.get_temp_file(config.CVS_CHECKOUT_DB),
            DB_OPEN_NEW,
            serializer,
        )

        # The set of CVSFile instances whose TextRecords have already been
        # read:
        self._loaded_files = set()

        # A map { CVSFILE : _FileTree } for files that currently have live
        # revisions:
        self._text_record_db = TextRecordDatabase(self._delta_db, self._co_db)

    def _get_text_record(self, cvs_rev):
        """Return the TextRecord instance for CVS_REV.

    If the TextRecords for CVS_REV.cvs_file haven't been loaded yet,
    do so now."""

        if cvs_rev.cvs_file not in self._loaded_files:
            for text_record in self._tree_db[cvs_rev.cvs_file.id].itervalues():
                self._text_record_db.add(text_record)
            self._loaded_files.add(cvs_rev.cvs_file)

        return self._text_record_db[cvs_rev.id]

    def get_content(self, cvs_rev):
        """Check out the text for revision C_REV from the repository.

    Return the text.  If CVS_REV has a property _keyword_handling, use
    it to determine how to handle RCS keywords in the output:

        'collapsed' -- collapse keywords

        'expanded' -- expand keywords

        'untouched' -- output keywords in the form they are found in
            the RCS file

    Note that $Log$ never actually generates a log (which makes test
    'requires_cvs()' fail).

    Revisions may be requested in any order, but if they are not
    requested in dependency order the checkout database will become
    very large.  Revisions may be skipped.  Each revision may be
    requested only once."""

        try:
            text = self._get_text_record(cvs_rev).checkout(
                self._text_record_db)
        except MalformedDeltaException, (msg):
            raise FatalError('Malformed RCS delta in %s, revision %s: %s' %
                             (cvs_rev.cvs_file.rcs_path, cvs_rev.rev, msg))

        keyword_handling = cvs_rev.get_property('_keyword_handling')

        if keyword_handling == 'untouched':
            # Leave keywords in the form that they were checked in.
            pass
        elif keyword_handling == 'collapsed':
            text = collapse_keywords(text)
        elif keyword_handling == 'expanded':
            text = expand_keywords(text, cvs_rev)
        else:
            raise FatalError(
                'Undefined _keyword_handling property (%r) for %s' % (
                    keyword_handling,
                    cvs_rev,
                ))

        if Ctx().decode_apple_single:
            # Insert a filter to decode any files that are in AppleSingle
            # format:
            text = get_maybe_apple_single(text)

        eol_fix = cvs_rev.get_property('_eol_fix')
        if eol_fix:
            text = canonicalize_eol(text, eol_fix)

        return text
Exemple #30
0
 def register_artifacts(self, which_pass):
   GitRevisionWriter.register_artifacts(self, which_pass)
   if Ctx().revision_collector.blob_filename is None:
     artifact_manager.register_temp_file_needed(
       config.GIT_BLOB_DATAFILE, which_pass,
       )