jujutsu_lib/
commit_builder.rs

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
15use std::sync::Arc;
16
17use crate::backend::{self, BackendResult, ChangeId, CommitId, Signature, TreeId};
18use crate::commit::Commit;
19use crate::repo::{MutableRepo, Repo};
20use crate::settings::{JJRng, UserSettings};
21
22#[must_use]
23pub struct CommitBuilder<'repo> {
24    mut_repo: &'repo mut MutableRepo,
25    rng: Arc<JJRng>,
26    commit: backend::Commit,
27    rewrite_source: Option<Commit>,
28}
29
30impl CommitBuilder<'_> {
31    pub fn for_new_commit<'repo>(
32        mut_repo: &'repo mut MutableRepo,
33        settings: &UserSettings,
34        parents: Vec<CommitId>,
35        tree_id: TreeId,
36    ) -> CommitBuilder<'repo> {
37        let signature = settings.signature();
38        assert!(!parents.is_empty());
39        let rng = settings.get_rng();
40        let change_id = rng.new_change_id(mut_repo.store().change_id_length());
41        let commit = backend::Commit {
42            parents,
43            predecessors: vec![],
44            root_tree: tree_id,
45            change_id,
46            description: String::new(),
47            author: signature.clone(),
48            committer: signature,
49        };
50        CommitBuilder {
51            mut_repo,
52            rng,
53            commit,
54            rewrite_source: None,
55        }
56    }
57
58    pub fn for_rewrite_from<'repo>(
59        mut_repo: &'repo mut MutableRepo,
60        settings: &UserSettings,
61        predecessor: &Commit,
62    ) -> CommitBuilder<'repo> {
63        let mut commit = predecessor.store_commit().clone();
64        commit.predecessors = vec![predecessor.id().clone()];
65        commit.committer = settings.signature();
66        // If the user had not configured a name and email before but now they have,
67        // update the author fields with the new information.
68        if commit.author.name == UserSettings::user_name_placeholder() {
69            commit.author.name = commit.committer.name.clone();
70        }
71        if commit.author.email == UserSettings::user_email_placeholder() {
72            commit.author.email = commit.committer.email.clone();
73        }
74        CommitBuilder {
75            mut_repo,
76            commit,
77            rng: settings.get_rng(),
78            rewrite_source: Some(predecessor.clone()),
79        }
80    }
81
82    pub fn set_parents(mut self, parents: Vec<CommitId>) -> Self {
83        assert!(!parents.is_empty());
84        self.commit.parents = parents;
85        self
86    }
87
88    pub fn set_predecessors(mut self, predecessors: Vec<CommitId>) -> Self {
89        self.commit.predecessors = predecessors;
90        self
91    }
92
93    pub fn set_tree(mut self, tree_id: TreeId) -> Self {
94        self.commit.root_tree = tree_id;
95        self
96    }
97
98    pub fn set_change_id(mut self, change_id: ChangeId) -> Self {
99        self.commit.change_id = change_id;
100        self
101    }
102
103    pub fn generate_new_change_id(mut self) -> Self {
104        self.commit.change_id = self
105            .rng
106            .new_change_id(self.mut_repo.store().change_id_length());
107        self
108    }
109
110    pub fn set_description(mut self, description: impl Into<String>) -> Self {
111        self.commit.description = description.into();
112        self
113    }
114
115    pub fn set_author(mut self, author: Signature) -> Self {
116        self.commit.author = author;
117        self
118    }
119
120    pub fn set_committer(mut self, committer: Signature) -> Self {
121        self.commit.committer = committer;
122        self
123    }
124
125    pub fn write(self) -> BackendResult<Commit> {
126        let mut rewrite_source_id = None;
127        if let Some(rewrite_source) = self.rewrite_source {
128            if *rewrite_source.change_id() == self.commit.change_id {
129                rewrite_source_id.replace(rewrite_source.id().clone());
130            }
131        }
132        let commit = self.mut_repo.write_commit(self.commit)?;
133        if let Some(rewrite_source_id) = rewrite_source_id {
134            self.mut_repo
135                .record_rewritten_commit(rewrite_source_id, commit.id().clone())
136        }
137        Ok(commit)
138    }
139}