code.gitea.io/gitea@v1.22.3/modules/lfs/filesystem_client.go (about)

     1  // Copyright 2021 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package lfs
     5  
     6  import (
     7  	"context"
     8  	"io"
     9  	"net/url"
    10  	"os"
    11  	"path/filepath"
    12  
    13  	"code.gitea.io/gitea/modules/util"
    14  )
    15  
    16  // FilesystemClient is used to read LFS data from a filesystem path
    17  type FilesystemClient struct {
    18  	lfsDir string
    19  }
    20  
    21  // BatchSize returns the preferred size of batchs to process
    22  func (c *FilesystemClient) BatchSize() int {
    23  	return 1
    24  }
    25  
    26  func newFilesystemClient(endpoint *url.URL) *FilesystemClient {
    27  	path, _ := util.FileURLToPath(endpoint)
    28  	lfsDir := filepath.Join(path, "lfs", "objects")
    29  	return &FilesystemClient{lfsDir}
    30  }
    31  
    32  func (c *FilesystemClient) objectPath(oid string) string {
    33  	return filepath.Join(c.lfsDir, oid[0:2], oid[2:4], oid)
    34  }
    35  
    36  // Download reads the specific LFS object from the target path
    37  func (c *FilesystemClient) Download(ctx context.Context, objects []Pointer, callback DownloadCallback) error {
    38  	for _, object := range objects {
    39  		p := Pointer{object.Oid, object.Size}
    40  
    41  		objectPath := c.objectPath(p.Oid)
    42  
    43  		f, err := os.Open(objectPath)
    44  		if err != nil {
    45  			return err
    46  		}
    47  		defer f.Close()
    48  		if err := callback(p, f, nil); err != nil {
    49  			return err
    50  		}
    51  	}
    52  	return nil
    53  }
    54  
    55  // Upload writes the specific LFS object to the target path
    56  func (c *FilesystemClient) Upload(ctx context.Context, objects []Pointer, callback UploadCallback) error {
    57  	for _, object := range objects {
    58  		p := Pointer{object.Oid, object.Size}
    59  
    60  		objectPath := c.objectPath(p.Oid)
    61  
    62  		if err := os.MkdirAll(filepath.Dir(objectPath), os.ModePerm); err != nil {
    63  			return err
    64  		}
    65  
    66  		content, err := callback(p, nil)
    67  		if err != nil {
    68  			return err
    69  		}
    70  
    71  		err = func() error {
    72  			defer content.Close()
    73  
    74  			f, err := os.Create(objectPath)
    75  			if err != nil {
    76  				return err
    77  			}
    78  			defer f.Close()
    79  			_, err = io.Copy(f, content)
    80  
    81  			return err
    82  		}()
    83  		if err != nil {
    84  			return err
    85  		}
    86  	}
    87  	return nil
    88  }