Hi Stefan.
I'm just about starting to get the idea that I think you're talking about, but I'm still having a hard time seeing how a state machine in the library would need more than one state transition for any chosen resolution, or why it would need to control information-display requests.
I think it would help if we could see how these ideas work, step by step, for some non-trivial use case.
Stefan Sperling wrote:
> On Thu, May 17, 2012 at 11:09:48AM +0100, Julian Foad wrote:
>> Let's take a closer look at what the user (through the client
>> application) needs to be able to do.
>
> Thanks for your comments. I think we're about to each consensus
> on this. We just have a slight misunderstanding to clear up, and
> need to agree on whether the main resolution logic should be
> implemented by clients themselves, or in the library.
>
>>> /* The set of all conflict choices for all kinds of conflicts. */
>>> enum svn_client_resolution_choice_t {
[...]
>>> svn_client_resolution_choice_theirs_conflict,
>>> svn_client_resolution_choice_mine_conflict,
>>
>> "theirs-conflict" and "mine-conflict" are good options for an
>> interactive 3-way merge tool to offer the user while showing the user
>> which sections of the file do have conflicts and which don't. It's not
>> an option I'd like to choose outside a 3-way merge tool. In terms of
>> tree conflicts, the same applies: I'd only be comfortable with this
>> option when it's presented in a 3-way directory-merge window that's
>> showing me which children are conflicting and which are not. After
>> pressing this button in the 3-way (file or dir) merge tool, I wouldn't
>> expect the tool to immediately close and Subversion library to
>> immediately finalize my choice, instead I'd expect to be able to review
>> and edit the result and then finally confirm.
>
> Agreed.
You agree that those options shouldn't be found outside a 3-way merge tool that's displaying the conflicts in question? So what are they doing in this list?
>>> [...]
>>> svn_client_resolution_choice_diff_full,
>>
>> "diff-full" isn't a resolution choice, it's the user asking to see
>> more information before choosing.
>
> There seems to be a slight misunderstanding here.
>
> I don't intend the values of this enum to represent "final"
> resolution choices.
OK, I'm glad to learn this was partly me misunderstanding your intentions.
> Rather, each choice allows the conflict
> resolver to make progress in the resolution process. Some
> options may result in a "final" resolution state where the
> conflict is resolved. Other options may simply allow the user
> to request information or carry out other actions that are
> in the set of permitted options of the current resolver state.
Perhaps you could give an example of one part of this state machine, that's sufficiently complex that a state machine is a useful way of achieving it. What's an example of when an information-display request such as "show me a diff between base and theirs" needs to be tied into the state machine?
> In technical terms, I think of the new resolver as a state machine,
> where each conflict choice triggers a state transition. The set of
> final states may either resolve the conflict or postpone resolution.
>
> Maybe we need a different name than svn_client_resolution_choice_t to
> avoid this misunderstanding? Note that it isn't called
> svn_client_final_resolution_choice_t :)
>
> Wherever you say "not a resolution" below, my above response applies.
>
>> We need to get away from the mode
>> of operation of the existing interactive resolver loop where the user
>> interacts my means of question-and-answer. That question-and-answer
>> loop should be in the presentation layer (svn), not in the library.
>
> Here I disagree. The loop we have today is a small state machine
> that runs within the 'svn' client. We need this loop in one form
> or another, either in the client or in the library. Today it is in
> the client, so each client has to reimplement this loop with a set of
> possible states and transitions. You seem to favour this model but I
> don't see any advantage in keeping it.
>
> I want to put as many aspects of the resolution process as possible
> into the library so that each client uses the same state machine to
> resolve conflicts. This makes it easier to work with several clients
> simultaneously because terminology and logic will be the same for all
> clients during the conflict resolution process. And it allows clients
> to implement conflict resolution dialogs with much less effort.
>
>>> svn_client_resolution_choice_edit_file,
>>
>> "edit-file" isn't a resolution choice that the library can then
>> "execute" in a black-box manner. Instead, the user wants the GUI to
>> help him/her prepare the final result with the aid of an editor, and
>> then the user may choose to confirm that resulting file as the final
>> resolved result. The resolution needs to be communicated to the Svn
>> lib in the form of a file, not "he chose 'edit' as the resolution".
>
> Yes, the library will receive a file.
>
> However, it will also have an internal resolver state that makes the
> acceptance of such a file a valid resolution choice. For example, it
> probably makes no sense to provide a file when resolving a directory
> vs. directory tree conflict. If the resolver knows the set of valid
> options for the conflict in question, it can reject such invalid input
> from clients. Your opinion seems to be that the decision about whether
> a choice is valid or not belongs into the client. I say that leads to
> unnecessary complexity and variance between client implementations.
>
>>> [...]
>>> svn_client_resolution_choice_scan_log_for_moves,
>>
>> Not a resolution. Instead, there should be a way for the GUI to get the
>> suggestion(s) of what moves might be applicable, and to offer those as
>> suggestions to the user, and then for the user to select maybe one of
>> the choices or maybe another resolution.
>
> Again, this is a good description of what I intend to do. It seems
> we're on the same page but you misunderstood my intentions.
>
>>> svn_client_resolution_choice_specify_local_target_for_incoming_move,
>>> svn_client_resolution_choice_merge_edits_into_local_file,
>>> [...]
>>> };
>>
>> A GUI wants the user to be in control. The first obvious thing is the
>> user should be able to select which file/dir to resolve next. If the
>> GUI wants to have a button that enters a loop that iterates over all
>> conflicts sequentially, that's it's business and we should make it
>> possible to do that, but we should not implement this loop in the Svn
>> lib.
>
> I realised after comments from Bert and Mark that we need to run the
> main loop of the resolution process within the client, not within the
> library. So I've ditched the callback-table idea in favour of a set of
> functions that receive a resolver state object which is opaque to the
> client (I'll elaborate on that in a different post). This way, the library
> can keep state and reject invalid or nonsense choices it receives
> from the client, and clients are in control of the overall flow.
>
>> The overall process the user goes through to resolve a particular
>> conflict needs to include a reviewing phase, an editing phase, and
>> finally a confirmation that the result is as the user wants it. How
>> does this fit with the idea of there being a point where the user
>> chooses a resolution such as "choose edit-file"?
>
> It fits because "choose edit-file" is just a state transition,
> rather than a final choice.
>
>> While in the reviewing phase of resolving any particular conflict, the
>> user should be able to bring up, on demand, a diff between 'mine' and
>> 'base' or 'mine:theirs' or 'base:theirs' or whatever he/she chooses,
>> jump to the location in their editor where the next text conflict
>> occurs, review the log messages on the source and/or target branch,
>> and so on. And all of this in parallel, in separate, non-modal
>> windows.
>
> Indeed, clients should be allowed to do all that. Do you think we even
> need to design the API such that clients can resolve multiple conflicts
> in parallel?
Yes.
> Or should we restrict clients to handle one conflict at
> a time?
No.
> This restriction might make it easier to implement the resolver.
> We could also make this restriction initially and lift it later.
You can only lift such a restriction if the initial architecture was designed for parallel resolving.
>> To enable this, the application needs access to the metadata
>> [...] like this:
>>
>> svn_node_kind_t node_kind;
>> svn_wc_conflict_kind_t kind;
>>
>> svn_wc_conflict_action_t action;
>> svn_wc_conflict_reason_t reason;
>> svn_wc_operation_t operation;
[...]
>> const svn_wc_conflict_version_t *src_left_version;
>> const svn_wc_conflict_version_t *src_right_version;
>>
>> ... which is an extract from svn_wc_conflict_description2_t.[...]
>
> This is the kind of data the resolver can use to determine a set of
> valid states and transitions for conflict resolution.
>
> The client will drive the state machine so just giving it an
> svn_wc_conflict_description2_t struct an insufficient client<->library
> interface. At the very least, we must also force clients to pass back
> in any state the resolver needs to keep.
>
> Does all that make sense?
Well, I'm not convinced yet.
- Julian
Received on 2012-05-23 14:47:41 CEST