Source code for swh.loader.svn.directory

# Copyright (C) 2023-2024  The Software Heritage developers
# See the AUTHORS file at the top-level directory of this distribution
# License: GNU General Public License version 3, or any later version
# See top-level LICENSE file for more information

"""Loader in charge of injecting tree at a specific revision.

"""

from datetime import datetime
import os
from pathlib import Path
import tempfile
from typing import Iterator, List, Optional

from swh.loader.core.loader import BaseDirectoryLoader
from swh.loader.svn.svn_repo import SvnRepo, get_svn_repo
from swh.model.model import Snapshot, SnapshotBranch, TargetType


[docs] class SvnExportLoader(BaseDirectoryLoader): """Load a svn tree at a specific svn revision into the swh archive. It is also possible to load a subset of the source tree by explicitly specifying the sub-paths to export in the ``svn_paths`` optional parameter. If the origin URL should be different from the subversion URL, the latter can be provided using the optional ``svn_url`` parameter. The output snapshot is of the form: .. code:: id: <bytes> branches: HEAD: target_type: alias target: rev_<svn-revision> rev_<svn-revision>: target_type: directory target: <directory-id> """ visit_type = "svn-export" def __init__( self, *args, svn_paths: Optional[List[str]] = None, svn_url: Optional[str] = None, **kwargs, ): self.svn_revision = kwargs.pop("ref") self.svn_paths = svn_paths super().__init__(*args, **kwargs) self.svn_url = svn_url if self.svn_url is None: self.svn_url = self.origin.url self.svnrepo: Optional[SvnRepo] = None
[docs] def prepare(self) -> None: self.svnrepo = get_svn_repo(self.svn_url) super().prepare()
[docs] def cleanup(self) -> None: """Clean up any intermediary fs.""" if self.svnrepo: self.svnrepo.clean_fs()
[docs] def fetch_artifact(self) -> Iterator[Path]: """Prepare the svn local repository checkout at a given commit/tag.""" assert self.svnrepo is not None if self.svn_paths is None: _, local_url = self.svnrepo.export_temporary(self.svn_revision) yield Path(local_url.decode()) else: assert self.svn_url is not None self.log.debug( "Exporting from the svn source tree rooted at %s@%s the sub-paths: %s", self.svn_url, self.svn_revision, ", ".join(self.svn_paths), ) with tempfile.TemporaryDirectory( suffix="-" + datetime.now().isoformat() ) as tmp_dir: for svn_path in self.svn_paths: svn_url = os.path.join(self.svn_url, svn_path.strip("/")) export_path = os.path.join(tmp_dir, svn_path.strip("/")) os.makedirs("/".join(export_path.split("/")[:-1]), exist_ok=True) self.svnrepo.export( svn_url, export_path, rev=int(self.svn_revision), remove_dest_path=False, overwrite=True, ignore_externals=True, ignore_keywords=True, ) yield Path(tmp_dir)
[docs] def build_snapshot(self) -> Snapshot: """Build snapshot without losing the svn revision context.""" assert self.directory is not None branch_name = f"rev_{self.svn_revision}".encode() return Snapshot( branches={ b"HEAD": SnapshotBranch( target_type=TargetType.ALIAS, target=branch_name, ), branch_name: SnapshotBranch( target_type=TargetType.DIRECTORY, target=self.directory.hash, ), } )