Ejemplo n.º 1
0
def test_init_repository(tmp_path):
    repo_path = tmp_path / "test_repo"
    repo_path.mkdir()

    repo = KartRepo.init_repository(repo_path)

    assert (repo_path / ".git").is_file()
    assert (repo_path / ".git").read_text() == "gitdir: .kart\n"
    assert (repo_path / ".kart").is_dir()
    assert (repo_path / ".kart" / "HEAD").exists()

    assert (repo_path / ".kart" / "index").read_bytes() == LOCKED_GIT_INDEX_CONTENTS[
        "kart"
    ]

    assert repo.config.get_int("kart.repostructure.version") == 3
    assert repo.config["kart.workingcopy.location"] == "test_repo.gpkg"
    assert repo.config.get_bool("core.bare") is False
Ejemplo n.º 2
0
def upgrade(ctx, source, dest, in_place):
    """
    Upgrade a repository for an earlier version of Kart to be compatible with the latest version.
    The current repository structure of Kart is known as Datasets V2, which is used from kart/Kart 0.5 onwards.

    Usage:
    kart upgrade SOURCE DEST
    """
    source = Path(source)
    dest = Path(dest)

    if in_place:
        dest = source

    if not in_place and dest.exists() and any(dest.iterdir()):
        raise InvalidOperation(f'"{dest}" isn\'t empty', param_hint="DEST")

    try:
        source_repo = KartRepo(source)
    except NotFound:
        raise click.BadParameter(
            f"'{source}': not an existing Kart repository",
            param_hint="SOURCE")

    source_version = source_repo.table_dataset_version
    if source_version == DEFAULT_NEW_REPO_VERSION:
        raise InvalidOperation(
            f"Cannot upgrade: source repository is already at latest known version (Datasets V{source_version})"
        )

    if source_version > DEFAULT_NEW_REPO_VERSION:
        # Repo is too advanced for this version of Kart to understand, we can't upgrade it.
        # This prints a good error messsage explaining the whole situation.
        source_repo.ensure_supported_version()

    source_dataset_class = dataset_class_for_legacy_version(
        source_version, in_place)

    if not source_dataset_class:
        raise InvalidOperation(
            f"Unrecognised source repository version: {source_version}")

    # action!
    if in_place:
        dest_repo = ForceLatestVersionRepo(dest)
    else:
        click.secho(f"Initialising {dest} ...", bold=True)
        dest.mkdir()
        dest_repo = KartRepo.init_repository(dest,
                                             wc_location=None,
                                             bare=source_repo.is_bare)

    # walk _all_ references
    source_walker = source_repo.walk(
        None, pygit2.GIT_SORT_TOPOLOGICAL | pygit2.GIT_SORT_REVERSE)
    for ref in source_repo.listall_reference_objects():
        source_walker.push(ref.resolve().target)

    commit_map = {}

    click.secho("\nWriting new commits ...", bold=True)
    i = -1
    for i, source_commit in enumerate(source_walker):
        dest_parents = []
        for parent_id in source_commit.parent_ids:
            try:
                dest_parents.append(commit_map[parent_id.hex])
            except KeyError:
                raise ValueError(
                    f"Commit {i} ({source_commit.id}): Haven't seen parent ({parent_id})"
                )

        _upgrade_commit(
            ctx,
            i,
            source_repo,
            source_commit,
            source_dataset_class,
            dest_parents,
            dest_repo,
            commit_map,
        )

    click.echo(f"{i+1} commits processed.")

    click.secho("\nUpdating references ...", bold=True)
    for ref in source_repo.listall_reference_objects():
        if ref.type == pygit2.GIT_REF_OID:
            # real references
            target = commit_map[ref.target.hex]
            dest_repo.references.create(ref.name, target, True)  # overwrite
            click.echo(f"  {ref.name} ({ref.target.hex[:8]} → {target[:8]})")

    for ref in source_repo.listall_reference_objects():
        if ref.type == pygit2.GIT_REF_SYMBOLIC:
            dest_repo.references.create(ref.name, ref.target)
            click.echo(f"  {ref.name} → {ref.target}")

    if i >= 0:
        if source_repo.head_is_detached:
            dest_repo.set_head(
                pygit2.Oid(hex=commit_map[source_repo.head.target.hex]))
        else:
            dest_repo.set_head(source_repo.head.name)

        click.secho("\nCompacting repository ...", bold=True)
        if in_place:
            # old reflogs will refer to old objects, which prevents them from getting gc'd.
            # so we clear out the old reflogs here.
            # this *does* mean you can't go back, hence the 'irreversible' in the --in-place help.
            dest_repo.invoke_git("reflog", "expire",
                                 "--expire-unreachable=now", "--all")

        dest_repo.gc("--prune=now")

    if source_repo.workingcopy_location:
        click.secho("\nCreating working copy ...", bold=True)
        subctx = click.Context(ctx.command, parent=ctx)
        subctx.ensure_object(context.Context)
        subctx.obj.user_repo_path = str(dest)
        subctx.invoke(checkout.create_workingcopy)

    if in_place:
        dest_repo.config[KartConfigKeys.KART_REPOSTRUCTURE_VERSION] = str(
            DEFAULT_NEW_REPO_VERSION)

    click.secho("\nUpgrade complete", fg="green", bold=True)