2016-05-26 20:29:36 +00:00
package commands
import (
2019-03-28 09:12:33 +00:00
"io"
2016-08-30 20:43:21 +00:00
"os"
2017-02-23 20:55:04 +00:00
"sort"
"strings"
2016-08-30 20:43:21 +00:00
2021-09-01 19:41:10 +00:00
"github.com/git-lfs/git-lfs/v3/errors"
"github.com/git-lfs/git-lfs/v3/git"
"github.com/git-lfs/git-lfs/v3/locking"
"github.com/git-lfs/git-lfs/v3/tools"
2021-12-13 18:48:34 +00:00
"github.com/git-lfs/git-lfs/v3/tr"
2016-05-26 20:29:36 +00:00
"github.com/spf13/cobra"
)
var (
2016-05-27 20:53:14 +00:00
locksCmdFlags = new ( locksFlags )
2016-05-26 20:29:36 +00:00
)
func locksCommand ( cmd * cobra . Command , args [ ] string ) {
2016-05-27 22:19:16 +00:00
filters , err := locksCmdFlags . Filters ( )
if err != nil {
2021-12-13 18:48:34 +00:00
Exit ( tr . Tr . Get ( "Error building filters: %v" , err ) )
2016-05-27 22:19:16 +00:00
}
2017-10-27 21:07:32 +00:00
if len ( lockRemote ) > 0 {
cfg . SetRemote ( lockRemote )
}
2018-01-05 22:22:25 +00:00
refUpdate := git . NewRefUpdate ( cfg . Git , cfg . PushRemote ( ) , cfg . CurrentRef ( ) , nil )
2017-10-27 21:07:32 +00:00
lockClient := newLockClient ( )
2017-12-07 01:08:18 +00:00
lockClient . RemoteRef = refUpdate . Right ( )
2016-12-05 15:01:25 +00:00
defer lockClient . Close ( )
2017-01-03 21:13:59 +00:00
2018-10-08 07:32:43 +00:00
if locksCmdFlags . Cached {
if locksCmdFlags . Limit > 0 {
2021-12-13 18:48:34 +00:00
Exit ( tr . Tr . Get ( "--cached option can't be combined with --limit" ) )
2018-10-08 07:32:43 +00:00
}
if len ( filters ) > 0 {
2021-12-13 18:48:34 +00:00
Exit ( tr . Tr . Get ( "--cached option can't be combined with filters" ) )
2018-10-08 07:32:43 +00:00
}
if locksCmdFlags . Local {
2021-12-13 18:48:34 +00:00
Exit ( tr . Tr . Get ( "--cached option can't be combined with --local" ) )
2018-10-08 07:32:43 +00:00
}
}
2019-03-28 09:12:33 +00:00
if locksCmdFlags . Verify {
if len ( filters ) > 0 {
2021-12-13 18:48:34 +00:00
Exit ( tr . Tr . Get ( "--verify option can't be combined with filters" ) )
2019-03-28 09:12:33 +00:00
}
if locksCmdFlags . Local {
2021-12-13 18:48:34 +00:00
Exit ( tr . Tr . Get ( "--verify option can't be combined with --local" ) )
2019-03-28 09:12:33 +00:00
}
}
var locks [ ] locking . Lock
var locksOwned map [ locking . Lock ] bool
var jsonWriteFunc func ( io . Writer ) error
if locksCmdFlags . Verify {
var ourLocks , theirLocks [ ] locking . Lock
2019-03-28 09:12:41 +00:00
ourLocks , theirLocks , err = lockClient . SearchLocksVerifiable ( locksCmdFlags . Limit , locksCmdFlags . Cached )
2019-03-28 09:12:33 +00:00
jsonWriteFunc = func ( writer io . Writer ) error {
return lockClient . EncodeLocksVerifiable ( ourLocks , theirLocks , writer )
}
locks = append ( ourLocks , theirLocks ... )
locksOwned = make ( map [ locking . Lock ] bool )
for _ , lock := range ourLocks {
locksOwned [ lock ] = true
}
} else {
locks , err = lockClient . SearchLocks ( filters , locksCmdFlags . Limit , locksCmdFlags . Local , locksCmdFlags . Cached )
jsonWriteFunc = func ( writer io . Writer ) error {
return lockClient . EncodeLocks ( locks , writer )
}
}
2016-11-28 17:01:06 +00:00
// Print any we got before exiting
2016-08-30 20:43:21 +00:00
if locksCmdFlags . JSON {
2019-03-28 09:12:33 +00:00
if err := jsonWriteFunc ( os . Stdout ) ; err != nil {
2016-08-30 20:43:21 +00:00
Error ( err . Error ( ) )
}
return
}
2017-02-27 21:16:34 +00:00
var maxPathLen int
var maxNameLen int
2017-02-23 20:55:04 +00:00
lockPaths := make ( [ ] string , 0 , len ( locks ) )
locksByPath := make ( map [ string ] locking . Lock )
2016-11-28 17:01:06 +00:00
for _ , lock := range locks {
2017-02-23 20:55:04 +00:00
lockPaths = append ( lockPaths , lock . Path )
locksByPath [ lock . Path ] = lock
2017-02-27 21:16:34 +00:00
maxPathLen = tools . MaxInt ( maxPathLen , len ( lock . Path ) )
if lock . Owner != nil {
maxNameLen = tools . MaxInt ( maxNameLen , len ( lock . Owner . Name ) )
}
2017-02-23 20:55:04 +00:00
}
sort . Strings ( lockPaths )
for _ , lockPath := range lockPaths {
2017-02-27 21:16:34 +00:00
var ownerName string
2017-02-23 20:55:04 +00:00
lock := locksByPath [ lockPath ]
2017-02-27 21:16:34 +00:00
if lock . Owner != nil {
ownerName = lock . Owner . Name
}
pathPadding := tools . MaxInt ( maxPathLen - len ( lock . Path ) , 0 )
namePadding := tools . MaxInt ( maxNameLen - len ( ownerName ) , 0 )
2019-03-28 09:12:33 +00:00
kind := ""
if locksOwned != nil {
if locksOwned [ lock ] {
kind = "O "
} else {
kind = " "
}
}
Print ( "%s%s%s\t%s%s\tID:%s" , kind , lock . Path , strings . Repeat ( " " , pathPadding ) ,
2017-02-27 21:16:34 +00:00
ownerName , strings . Repeat ( " " , namePadding ) ,
lock . Id ,
)
2016-05-26 20:29:36 +00:00
}
2016-11-28 15:12:47 +00:00
if err != nil {
2021-12-13 18:48:34 +00:00
Exit ( tr . Tr . Get ( "Error while retrieving locks: %v" , errors . Cause ( err ) ) )
2016-05-26 20:29:36 +00:00
}
}
// locksFlags wraps up and holds all of the flags that can be given to the
// `git lfs locks` command.
type locksFlags struct {
// Path is an optional filter parameter to filter against the lock's
// path
Path string
// Id is an optional filter parameter used to filtere against the lock's
// ID.
Id string
// limit is an optional request parameter sent to the server used to
// limit the
Limit int
2016-12-05 18:16:30 +00:00
// local limits the scope of lock reporting to the locally cached record
// of locks for the current user & doesn't query the server
Local bool
2016-08-30 20:43:21 +00:00
// JSON is an optional parameter to output data in json format.
JSON bool
2018-10-08 07:32:43 +00:00
// for non-local queries, report cached query results from the last query
// instead of actually querying the server again
Cached bool
2019-03-28 09:12:33 +00:00
// for non-local queries, verify lock owner on server and
// denote our locks in output
Verify bool
2016-05-26 20:29:36 +00:00
}
2016-11-28 15:12:47 +00:00
// Filters produces a filter based on locksFlags instance.
func ( l * locksFlags ) Filters ( ) ( map [ string ] string , error ) {
filters := make ( map [ string ] string )
2016-05-26 20:29:36 +00:00
if l . Path != "" {
2016-05-27 22:19:16 +00:00
path , err := lockPath ( l . Path )
if err != nil {
return nil , err
}
2016-11-28 15:12:47 +00:00
filters [ "path" ] = path
2016-05-26 20:29:36 +00:00
}
if l . Id != "" {
2016-11-28 15:12:47 +00:00
filters [ "id" ] = l . Id
2016-05-26 20:29:36 +00:00
}
2016-05-27 22:19:16 +00:00
return filters , nil
2016-05-26 20:29:36 +00:00
}
2016-08-10 15:33:25 +00:00
func init ( ) {
2016-09-01 16:09:38 +00:00
RegisterCommand ( "locks" , locksCommand , func ( cmd * cobra . Command ) {
2021-12-13 18:48:34 +00:00
cmd . Flags ( ) . StringVarP ( & lockRemote , "remote" , "r" , "" , "specify which remote to use when interacting with locks" )
2016-08-10 15:33:25 +00:00
cmd . Flags ( ) . StringVarP ( & locksCmdFlags . Path , "path" , "p" , "" , "filter locks results matching a particular path" )
cmd . Flags ( ) . StringVarP ( & locksCmdFlags . Id , "id" , "i" , "" , "filter locks results matching a particular ID" )
cmd . Flags ( ) . IntVarP ( & locksCmdFlags . Limit , "limit" , "l" , 0 , "optional limit for number of results to return" )
2016-12-05 18:16:30 +00:00
cmd . Flags ( ) . BoolVarP ( & locksCmdFlags . Local , "local" , "" , false , "only list cached local record of own locks" )
2018-10-08 07:32:43 +00:00
cmd . Flags ( ) . BoolVarP ( & locksCmdFlags . Cached , "cached" , "" , false , "list cached lock information from the last remote query, instead of actually querying the server" )
2019-03-28 09:12:33 +00:00
cmd . Flags ( ) . BoolVarP ( & locksCmdFlags . Verify , "verify" , "" , false , "verify lock owner on server and mark own locks by 'O'" )
2016-08-30 20:43:21 +00:00
cmd . Flags ( ) . BoolVarP ( & locksCmdFlags . JSON , "json" , "" , false , "print output in json" )
2016-08-10 15:33:25 +00:00
} )
}