github.com/git-lfs/git-lfs@v2.5.2+incompatible/commands/command_clean.go (about)

     1  package commands
     2  
     3  import (
     4  	"io"
     5  	"os"
     6  
     7  	"github.com/git-lfs/git-lfs/errors"
     8  	"github.com/git-lfs/git-lfs/lfs"
     9  	"github.com/git-lfs/git-lfs/tools"
    10  	"github.com/spf13/cobra"
    11  )
    12  
    13  // clean cleans an object read from the given `io.Reader`, "from", and writes
    14  // out a corresponding pointer to the `io.Writer`, "to". If there were any
    15  // errors encountered along the way, they will be returned immediately if the
    16  // error is non-fatal, otherwise they will halt using the built in
    17  // `commands.Panic`.
    18  //
    19  // If fileSize is given as a non-negative (>= 0) integer, that value is used
    20  // with preference to os.Stat(fileName).Size(). If it is given as negative, the
    21  // value from the `stat(1)` call will be used instead.
    22  //
    23  // If the object read from "from" is _already_ a clean pointer, then it will be
    24  // written out verbatim to "to", without trying to make it a pointer again.
    25  func clean(gf *lfs.GitFilter, to io.Writer, from io.Reader, fileName string, fileSize int64) (*lfs.Pointer, error) {
    26  	var cb tools.CopyCallback
    27  	var file *os.File
    28  
    29  	if len(fileName) > 0 {
    30  		stat, err := os.Stat(fileName)
    31  		if err == nil && stat != nil {
    32  			if fileSize < 0 {
    33  				fileSize = stat.Size()
    34  			}
    35  
    36  			localCb, localFile, err := gf.CopyCallbackFile("clean", fileName, 1, 1)
    37  			if err != nil {
    38  				Error(err.Error())
    39  			} else {
    40  				cb = localCb
    41  				file = localFile
    42  			}
    43  		}
    44  	}
    45  
    46  	cleaned, err := gf.Clean(from, fileName, fileSize, cb)
    47  	if file != nil {
    48  		file.Close()
    49  	}
    50  
    51  	if cleaned != nil {
    52  		defer cleaned.Teardown()
    53  	}
    54  
    55  	if errors.IsCleanPointerError(err) {
    56  		// If the contents read from the working directory was _already_
    57  		// a pointer, we'll get a `CleanPointerError`, with the context
    58  		// containing the bytes that we should write back out to Git.
    59  
    60  		_, err = to.Write(errors.GetContext(err, "bytes").([]byte))
    61  		return nil, err
    62  	}
    63  
    64  	if err != nil {
    65  		ExitWithError(errors.Wrap(err, "Error cleaning LFS object"))
    66  	}
    67  
    68  	tmpfile := cleaned.Filename
    69  	mediafile, err := gf.ObjectPath(cleaned.Oid)
    70  	if err != nil {
    71  		Panic(err, "Unable to get local media path.")
    72  	}
    73  
    74  	if stat, _ := os.Stat(mediafile); stat != nil {
    75  		if stat.Size() != cleaned.Size && len(cleaned.Pointer.Extensions) == 0 {
    76  			Exit("Files don't match:\n%s\n%s", mediafile, tmpfile)
    77  		}
    78  		Debug("%s exists", mediafile)
    79  	} else {
    80  		if err := os.Rename(tmpfile, mediafile); err != nil {
    81  			Panic(err, "Unable to move %s to %s\n", tmpfile, mediafile)
    82  		}
    83  
    84  		Debug("Writing %s", mediafile)
    85  	}
    86  
    87  	_, err = lfs.EncodePointer(to, cleaned.Pointer)
    88  	return cleaned.Pointer, err
    89  }
    90  
    91  func cleanCommand(cmd *cobra.Command, args []string) {
    92  	requireStdin("This command should be run by the Git 'clean' filter")
    93  	installHooks(false)
    94  
    95  	var fileName string
    96  	if len(args) > 0 {
    97  		fileName = args[0]
    98  	}
    99  
   100  	gitfilter := lfs.NewGitFilter(cfg)
   101  	ptr, err := clean(gitfilter, os.Stdout, os.Stdin, fileName, -1)
   102  	if err != nil {
   103  		Error(err.Error())
   104  	}
   105  
   106  	if ptr != nil && possiblyMalformedObjectSize(ptr.Size) {
   107  		Error("Possibly malformed conversion on Windows, see `git lfs help smudge` for more details.")
   108  	}
   109  }
   110  
   111  func init() {
   112  	RegisterCommand("clean", cleanCommand, nil)
   113  }