github.com/psexton/git-lfs@v2.1.1-0.20170517224304-289a18b2bc53+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/progress"
    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 the object read from "from" is _already_ a clean pointer, then it will be
    20  // written out verbatim to "to", without trying to make it a pointer again.
    21  func clean(to io.Writer, from io.Reader, fileName string) error {
    22  	var cb progress.CopyCallback
    23  	var file *os.File
    24  	var fileSize int64
    25  
    26  	if len(fileName) > 0 {
    27  		stat, err := os.Stat(fileName)
    28  		if err == nil && stat != nil {
    29  			fileSize = stat.Size()
    30  
    31  			localCb, localFile, err := lfs.CopyCallbackFile("clean", fileName, 1, 1)
    32  			if err != nil {
    33  				Error(err.Error())
    34  			} else {
    35  				cb = localCb
    36  				file = localFile
    37  			}
    38  		}
    39  	}
    40  
    41  	cleaned, err := lfs.PointerClean(from, fileName, fileSize, cb)
    42  	if file != nil {
    43  		file.Close()
    44  	}
    45  
    46  	if cleaned != nil {
    47  		defer cleaned.Teardown()
    48  	}
    49  
    50  	if errors.IsCleanPointerError(err) {
    51  		// If the contents read from the working directory was _already_
    52  		// a pointer, we'll get a `CleanPointerError`, with the context
    53  		// containing the bytes that we should write back out to Git.
    54  
    55  		_, err = to.Write(errors.GetContext(err, "bytes").([]byte))
    56  		return err
    57  	}
    58  
    59  	if err != nil {
    60  		ExitWithError(errors.Wrap(err, "Error cleaning LFS object"))
    61  	}
    62  
    63  	tmpfile := cleaned.Filename
    64  	mediafile, err := lfs.LocalMediaPath(cleaned.Oid)
    65  	if err != nil {
    66  		Panic(err, "Unable to get local media path.")
    67  	}
    68  
    69  	if stat, _ := os.Stat(mediafile); stat != nil {
    70  		if stat.Size() != cleaned.Size && len(cleaned.Pointer.Extensions) == 0 {
    71  			Exit("Files don't match:\n%s\n%s", mediafile, tmpfile)
    72  		}
    73  		Debug("%s exists", mediafile)
    74  	} else {
    75  		if err := os.Rename(tmpfile, mediafile); err != nil {
    76  			Panic(err, "Unable to move %s to %s\n", tmpfile, mediafile)
    77  		}
    78  
    79  		Debug("Writing %s", mediafile)
    80  	}
    81  
    82  	_, err = lfs.EncodePointer(to, cleaned.Pointer)
    83  	return err
    84  }
    85  
    86  func cleanCommand(cmd *cobra.Command, args []string) {
    87  	requireStdin("This command should be run by the Git 'clean' filter")
    88  	lfs.InstallHooks(false)
    89  
    90  	var fileName string
    91  	if len(args) > 0 {
    92  		fileName = args[0]
    93  	}
    94  
    95  	if err := clean(os.Stdout, os.Stdin, fileName); err != nil {
    96  		Error(err.Error())
    97  	}
    98  }
    99  
   100  func init() {
   101  	RegisterCommand("clean", cleanCommand, nil)
   102  }