drone/git/repack.go
Enver Biševac 5b86da53e8 feat: [CODE-3039]: git layer functions and methods (#4035)
* requested changes

* requested changes

* add header and nolint

* add gc args

* git layer functions and methods
2025-07-24 13:43:23 +00:00

143 lines
4.2 KiB
Go

// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package git
import (
"context"
"errors"
"fmt"
"path/filepath"
"time"
"github.com/harness/gitness/git/api"
"github.com/rs/zerolog/log"
)
type RepackStrategy string
const (
RepackStrategyIncrementalWithUnreachable RepackStrategy = "incremental_with_unreachable"
RepackStrategyFullWithCruft RepackStrategy = "full_with_cruft"
RepackStrategyFullWithUnreachable RepackStrategy = "full_with_unreachable"
RepackStrategyGeometric RepackStrategy = "geometric"
)
type RepackParams struct {
Strategy RepackStrategy
WriteBitmap bool
WriteMultiPackIndex bool
CruftExpireBefore time.Time
}
func (p RepackParams) Validate() error {
switch p.Strategy {
case RepackStrategyIncrementalWithUnreachable:
if p.WriteBitmap {
return errors.New("cannot create bitmap with incremental repack strategy")
}
if p.WriteMultiPackIndex {
return errors.New("cannot create multi-pack index with incremental repack strategy")
}
case RepackStrategyFullWithCruft:
if p.CruftExpireBefore.IsZero() {
return errors.New("cannot repack with cruft with empty expiration time")
}
case RepackStrategyFullWithUnreachable:
case RepackStrategyGeometric:
default:
return fmt.Errorf("unknown strategy: %q", p.Strategy)
}
return nil
}
func (s *Service) repackObjects(
ctx context.Context,
repoPath string,
params RepackParams,
) error {
if err := params.Validate(); err != nil {
return err
}
defer func() {
err := api.SetLastFullRepackTime(repoPath, time.Now())
if err != nil {
log.Ctx(ctx).Warn().Msgf("failed to set last full repack time: %s", err.Error())
}
}()
switch params.Strategy {
case RepackStrategyIncrementalWithUnreachable:
// Pack all loose objects into a new pack file, regardless of their reachability.
err := s.git.PackObjects(ctx, repoPath, api.PackObjectsParams{
PackLooseUnreachable: true,
Local: true,
Incremental: true,
NonEmpty: true,
Quiet: true,
}, filepath.Join(repoPath, "objects", "pack", "pack"))
if err != nil {
return fmt.Errorf("incremental with unreachable repack objects error: %w", err)
}
// ensure that packed loose objects are deleted.
err = s.git.PrunePacked(ctx, repoPath, api.PrunePackedParams{
Quiet: true,
})
if err != nil {
return fmt.Errorf("prune pack objects error: %w", err)
}
case RepackStrategyFullWithCruft:
repackParams := api.RepackParams{
Cruft: true,
PackKeptObjects: true,
Local: true,
RemoveRedundantObjects: true,
WriteMidx: params.WriteMultiPackIndex,
}
if !params.CruftExpireBefore.IsZero() {
repackParams.CruftExpireBefore = params.CruftExpireBefore
}
err := s.git.RepackObjects(ctx, repoPath, repackParams)
if err != nil {
return fmt.Errorf("full with cruft repack objects error: %w", err)
}
case RepackStrategyFullWithUnreachable:
err := s.git.RepackObjects(ctx, repoPath, api.RepackParams{
SinglePack: true,
Local: true,
RemoveRedundantObjects: true,
KeepUnreachable: true,
WriteMidx: params.WriteMultiPackIndex,
})
if err != nil {
return fmt.Errorf("full with unreachable repack objects error: %w", err)
}
case RepackStrategyGeometric:
err := s.git.RepackObjects(ctx, repoPath, api.RepackParams{
Geometric: 2,
RemoveRedundantObjects: true,
Local: true,
WriteMidx: params.WriteMultiPackIndex,
})
if err != nil {
return fmt.Errorf("geometric repack objects error: %w", err)
}
}
return nil
}