just playing with tangled
1// Copyright 2020 The Jujutsu Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#![allow(missing_docs)]
16
17use std::cmp::Ordering;
18use std::fmt::{Debug, Error, Formatter};
19use std::hash::{Hash, Hasher};
20use std::sync::Arc;
21
22use crate::backend;
23use crate::backend::{BackendError, ChangeId, CommitId, Signature, TreeId};
24use crate::merged_tree::MergedTree;
25use crate::repo_path::RepoPath;
26use crate::store::Store;
27use crate::tree::Tree;
28
29#[derive(Clone)]
30pub struct Commit {
31 store: Arc<Store>,
32 id: CommitId,
33 data: Arc<backend::Commit>,
34}
35
36impl Debug for Commit {
37 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
38 f.debug_struct("Commit").field("id", &self.id).finish()
39 }
40}
41
42impl PartialEq for Commit {
43 fn eq(&self, other: &Self) -> bool {
44 self.id == other.id
45 }
46}
47
48impl Eq for Commit {}
49
50impl Ord for Commit {
51 fn cmp(&self, other: &Self) -> Ordering {
52 self.id.cmp(&other.id)
53 }
54}
55
56impl PartialOrd for Commit {
57 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
58 Some(self.cmp(other))
59 }
60}
61
62impl Hash for Commit {
63 fn hash<H: Hasher>(&self, state: &mut H) {
64 self.id.hash(state)
65 }
66}
67
68impl Commit {
69 pub fn new(store: Arc<Store>, id: CommitId, data: Arc<backend::Commit>) -> Self {
70 Commit { store, id, data }
71 }
72
73 pub fn store(&self) -> &Arc<Store> {
74 &self.store
75 }
76
77 pub fn id(&self) -> &CommitId {
78 &self.id
79 }
80
81 pub fn parent_ids(&self) -> &[CommitId] {
82 &self.data.parents
83 }
84
85 pub fn parents(&self) -> Vec<Commit> {
86 self.data
87 .parents
88 .iter()
89 .map(|id| self.store.get_commit(id).unwrap())
90 .collect()
91 }
92
93 pub fn predecessor_ids(&self) -> &[CommitId] {
94 &self.data.predecessors
95 }
96
97 pub fn predecessors(&self) -> Vec<Commit> {
98 self.data
99 .predecessors
100 .iter()
101 .map(|id| self.store.get_commit(id).unwrap())
102 .collect()
103 }
104
105 // TODO(#1624): Delete when all callers use `merged_tree()`
106 pub fn tree(&self) -> Tree {
107 self.store
108 .get_tree(&RepoPath::root(), self.data.root_tree.as_legacy_tree_id())
109 .unwrap()
110 }
111
112 pub fn merged_tree(&self) -> Result<MergedTree, BackendError> {
113 if self.data.uses_tree_conflict_format {
114 let tree_conflict = self
115 .data
116 .root_tree
117 .try_map(|tree_id| self.store.get_tree(&RepoPath::root(), tree_id))?;
118 Ok(MergedTree::new(tree_conflict))
119 } else {
120 let tree_id = self.data.root_tree.as_legacy_tree_id();
121 let tree = self.store.get_tree(&RepoPath::root(), tree_id)?;
122 Ok(MergedTree::legacy(tree))
123 }
124 }
125
126 pub fn tree_id(&self) -> &TreeId {
127 self.data.root_tree.as_legacy_tree_id()
128 }
129
130 pub fn change_id(&self) -> &ChangeId {
131 &self.data.change_id
132 }
133
134 pub fn store_commit(&self) -> &backend::Commit {
135 &self.data
136 }
137
138 pub fn description(&self) -> &str {
139 &self.data.description
140 }
141
142 pub fn author(&self) -> &Signature {
143 &self.data.author
144 }
145
146 pub fn committer(&self) -> &Signature {
147 &self.data.committer
148 }
149
150 /// A commit is discardable if it has one parent, no change from its
151 /// parent, and an empty description.
152 pub fn is_discardable(&self) -> bool {
153 if self.description().is_empty() {
154 if let [parent_commit] = &*self.parents() {
155 return self.tree_id() == parent_commit.tree_id();
156 }
157 }
158 false
159 }
160}