Skip to content

Locking commands#1223

Merged
technoweenie merged 16 commits intogit-lfs:masterfrom
ttaylorr:locking-commands
May 17, 2016
Merged

Locking commands#1223
technoweenie merged 16 commits intogit-lfs:masterfrom
ttaylorr:locking-commands

Conversation

@ttaylorr
Copy link
Contributor

@ttaylorr ttaylorr commented May 16, 2016

This PR adds to @sinbad's original proposal and extends it to document some particular commands that we will have to teach the LFS client.

All of the documentation surrounding these new commands and API methods are in the contents of this PR, so I will keep this description brief 😄

Thanks in advance for reading! 👋

@ttaylorr
Copy link
Contributor Author

Hmm, after thinking more about this, I realized that will need to expand the API to cover the commit negotiation that @sinbad described in his original pull-request. I added partial support for this in 6864ac5, but I will have to think about a more flexible flow to support more implementations.

To make the implementing locking on the lfs-test-server as well as other servers
in the future easier, it makes sense to create a `lfs/lock` package that can be
depended upon from any server. This will go along with Steve's refactor which
touches the `lfs` package quite a bit.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the idea is that github.com/github/git-lfs/lfs is not a package that we want 3rd parties to use. This should be extracted to a top level package like github.com/github/git-lfs/lock. May make sense to call it github.com/github/git-lfs/lfslock so that it's obvious when callers use it:

lfslock.Lock{Path: "img/foo.psd", ...}

I dont'e care about the name so much, but I do want it as a top level package under the repo.

Copy link
Contributor Author

@ttaylorr ttaylorr May 16, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, but I think just lock should be fine. The generic nature of that package's name is more of a concern of any code that depends on it, not the LFS client itself. If someone that depends on this package and needs a more specific name, they can just rename their import:

import (
        lfslock github.com/github/git-lfs/lock
)

(Addressed in a7945e0).

@ttaylorr ttaylorr changed the title Locking commands [WIP] Locking commands May 16, 2016
// a lock associated with the given UUID.
type UnlockRequest struct {
// UUID is the identifier of the lock that the client wishes to remove.
UUID string `json:"path"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

json tag typo.

@ttaylorr
Copy link
Contributor Author

Demoting this PR to a [WIP] as I still have to consider some final thoughts for the lock-listing API. In particular:

Pagination is a bit of a tricky subject, since there is no guarantee that a client will get all of the locks they requested if a multipage response is returned and a new lock was created while paginating through the n-th page of that response. @technoweenie and I discussed that perhaps the best way around this was to eliminate the notion of "pages" and instead make it a requirement that the server return results in a reverse-chronological ordering. Clients could instead send the last UUID that they received and the server would send them n results after that, and we'd still keep the HasMore bool.

The other thing I have yet to decide upon is the filtering mechanism. The current filter definition that I proposed:

type Filter struct {                                               
        // Prop is the property to search against.         
        Prop Property `json:"prop"`                        
        // Value is the value that the property must take. 
        Value string `json:"value"`                        
}

works well for equality operations, but fails for <, >, and != operations. This is sort of a rabbit-hole, since once you consider adding operations for < and >, it's easy to add nested filters and ANDs, ORs, and XORs. I'm not sure how far we should take this idea, but if we pursue the idea of nested filters, I could work on an API to accommodate that.

@technoweenie
Copy link
Contributor

I like the type definitions, but I think it'd be helpful thinking about the API too. For example, I'm not sure unlocking will require a struct like this:

// An UnlockRequest is sent by the client over the API when they wish to remove
// a lock associated with the given UUID.
type UnlockRequest struct {
        // UUID is the identifier of the lock that the client wishes to remove.
        UUID string `json:"path"`
}

Given an LFS base url of https://git-server.com/repo/info/lfs, the unlock API call could be something like POST https://git-server.com/repo/info/lfs/locks/{uuid} -d {"operation":"unlock", ...}.

Also, I think the spec should recommend that server implementations keep locks for auditing purposes. This is why the unlock action is a POST to the resource, and not a DELETE.

// time that the lock stopped being active. If the lock is still active,
// the server can either a) not send this field, or b) send the
// zero-value of time.Time.
ExpiresAt time.Time `json:"expired_at,omitempty"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not clear on how this field is intended to work. The past tense on "time that the lock stopped being active" suggests it's only for historical reporting, so it would only be filled in after the user had deliberately unlocked the file? Or, are you intending on making locks time-limited so they unlock on their own? I think the latter would cause some issues, files unlocking on a time limit could increase the likelihood of accidental parallel changes - the 'break lock' function is intended to recover from cases where a lock is left active by someone else by accident.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if the key name should be UnlockedAt or something then? It'd likely only be shown when viewing an old lock by its UUID.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sinbad good point. I had mentioned to @technoweenie that I thought having a lock with a given expiry time would be tricky, since that adds an extra layer of complexity to the locking mechanism. My original intention with this field was make it so clients (and the server) would be able to determine which locks were active or not, while also maintaining a historical list of locks that had been placed for posterity.

The tense is a little weird here, so I think I'll adopt @technoweenie's suggestion and rename it to UnlockedAt, and still retain the omitempty property of the JSON tag. That way, we're not using nil as a value (by changing this field's type to *time.Time), and we have the benefit of Go's zero-type initialization that we can take advantage of with the time.IsZero method.

@ttaylorr
Copy link
Contributor Author

On second thought, the currently proposed filter API might be alright for V1. I'm not sure the >/< operators are that useful for anything other than created_at time. It would be nice to greater support for nested filters, but I move that we adopt the current model for now, and expand on it in v2 if we find a greater need for more filtering operations.

@ttaylorr ttaylorr force-pushed the locking-commands branch 2 times, most recently from 9fef524 to ce0abcf Compare May 17, 2016 16:31
@ttaylorr ttaylorr changed the title [WIP] Locking commands Locking commands May 17, 2016
@technoweenie
Copy link
Contributor

Merging this. Great job finishing the proposal, time to get crackin on a prototype 🤘

@technoweenie technoweenie merged commit 355eedc into git-lfs:master May 17, 2016
@ttaylorr
Copy link
Contributor Author

Thanks, @technoweenie! Let's do it.

@ttaylorr ttaylorr deleted the locking-commands branch May 17, 2016 19:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants