3.0 KB84 lines
Blame
1/**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8import type {CommitStackState} from './commitStackState';
9
10import {cached} from 'shared/LRU';
11import {firstLine, nullthrows} from 'shared/utils';
12import {Dag, DagCommitInfo} from '../dag/dag';
13import {WDIR_NODE, YOU_ARE_HERE_VIRTUAL_COMMIT} from '../dag/virtualCommit';
14
15/**
16 * Calculate a virtual "Dag" purely from "stack".
17 * The virtual "Dag" does not have to be a subset of the main dag being displayed.
18 * This avoids race conditions and various issues when the "stack" does not
19 * match the main dag.
20 * The nodes (commit hashes) of the returned dag is the "key" of commits in
21 * the "stack", not real commit hashes. This is to support various stack edit
22 * operations like splitting, inserting new commits, etc.
23 */
24function calculateDagFromStackImpl(stack: CommitStackState): Dag {
25 let dag = new Dag();
26
27 // Figure out the "dot" from the initial exported stack.
28 // "dot" is the parent of "wdir()".
29 // The exported stack might not have "wdir()" if not requested.
30 // Run `sl debugexportstack -r '.+wdir()' | python3 -m json.tool` to get a sense of the output.
31 let dotNode: string | undefined = undefined;
32 let dotKey: string | undefined = undefined;
33 for (const exportedCommit of stack.originalStack) {
34 if (exportedCommit.node === WDIR_NODE) {
35 dotNode = exportedCommit.parents?.at(0);
36 break;
37 }
38 }
39
40 if (dotNode != null) {
41 const maybeDotCommit = stack.stack.findLast(commit => commit.originalNodes.contains(dotNode));
42 if (maybeDotCommit != null) {
43 dotKey = maybeDotCommit.key;
44 const wdirRev = stack.findLastRev(commit => commit.originalNodes.contains(WDIR_NODE));
45 dag = dag.add([YOU_ARE_HERE_VIRTUAL_COMMIT.merge({parents: [dotKey], stackRev: wdirRev})]);
46 }
47 }
48
49 // Insert commits from the stack.
50 // Since we've already inserted the "wdir()" commit, skip it from the stack.
51 dag = dag.add(
52 stack
53 .revs()
54 .filter(rev => !stack.get(rev)?.originalNodes?.contains(WDIR_NODE))
55 .map(rev => {
56 const commit = nullthrows(stack.get(rev));
57 return DagCommitInfo.fromCommitInfo({
58 title: firstLine(commit.text),
59 hash: commit.key,
60 parents: commit.parents
61 .flatMap(parentRev => {
62 const parent = stack.get(parentRev);
63 return parent == null ? [] : [parent.key];
64 })
65 .toArray(),
66 phase: commit.immutableKind === 'hash' ? 'public' : 'draft',
67 author: commit.author,
68 date: new Date(commit.date.unix),
69 isDot: commit.key === dotKey,
70 stackRev: rev,
71 // Other fields are omitted for now, since nobody uses them yet.
72 });
73 }),
74 );
75
76 return dag;
77}
78
79/**
80 * Provides a `Dag` that just contains the `stack`.
81 * If `dotRev` is set, add a "YouAreHere" virtual commit as a child of the rev.
82 */
83export const calculateDagFromStack = cached(calculateDagFromStackImpl);
84