How many changes are shown is controlled by the –show-changes command line option and the unrecord_changes global option (the former takes precedence). As part of this change, the make_changelist and parse_changelist functions are moved from pushpull.rs to commands/mod.rs so that unrecord can use them.
SLJ3OHD4F6GJGZ3SV2D7DMR3PXYHPSI64X77KZ3RJ24EGEX6ZNQAC
62XVBWPYCBULZ2IUWF36JVHAPMKCGQC53PQQ53AAGZGC2KT7VQRQC
SE4RJYBZBNU6I3URBUMWP6T27CGGXLBEWWDB7WWX3W3AYSU6AFAAC
H23LO7U7MNB5GTLOUIFYAJ6DP57DM3VFBR4IBOAVPMHS356AYFPQC
BBKV6VMN4EVBCBSAQMTL2TARBBSQEZGRCXMTKYUIDOJ3HZISUP7AC
JWTT77WJIGJOZVLLZBADUDZIMSEAR7ZLYLWISOXFJJCNWJGJPWQQC
SXEYMYF7P4RZMZ46WPL4IZUTSQ2ATBWYZX7QNVMS3SGOYXYOHAGQC
L4JXJHWXYNCL4QGJXNKKTOKKTAXKKXBJUUY7HFZGEUZ5A2V5H34QC
5DVRL6MFXQOCPOZMYSKBERMRRVUTYRL2SRGRTU2MH4IEOFCDKM3QC
AEPEFS7O3YT7CRRFYQVJWUXUUSRGJ6K6XZQVK62B6N74UXOIFWYAC
YAJAXIV5VL263Z6FYLKFPROB3MQPRPH22P44GRGRVGEP56HOMBOAC
I52XSRUH5RVHQBFWVMAQPTUSPAJ4KNVID2RMI3UGCVKFLYUO6WZAC
IMCZFTIJ245E3JBOHAY3FMEZCGTL4VNIF26WAKJSZMQXZJ4NK3LAC
XWETQ4DE4KL2GQWSEBE5NENLTSLIDF7RIWOCCVWJFQOVQJE5P33AC
OAXTXEAFX6YLO2XX6L4VMCVW4YZSIXWL6QOZKQCDSL7M44QNX66AC
GUNVHCG3GTVBGGODDAHVZ5W552BS2IQEOKMAFGFNRTCZR6EPYWJAC
/// Unrecords all changes upto the given hash
/// Unrecords a list of changes.
///
/// The changes will be removed from your log, but your working
/// copy will stay exactly the same, unless the
/// `--reset` flag was passed. A change can only be unrecorded
/// if all changes that depend on it are also unrecorded in the
/// same operation. There are two ways to call `pijul-unrecord`:
///
/// * With a list of <change-id>s. The given changes will be
/// unrecorded, if possible.
///
/// * Without listing any <change-id>s. You will be
/// presented with a list of changes to choose from.
/// The length of the list is determined by the `unrecord_changes`
/// setting in your global config or the `--show-changes` option,
/// with the latter taking precedence.
/// Identifier of the change (unambiguous prefixes are accepted)
/// Show N changes in a text editor if no <change-id>s were given.
/// Defaults to the value
/// of `unrecord_changes` in your global configuration.
#[clap(long = "show-changes", value_name = "N", conflicts_with("change-id"))]
show_changes: Option<usize>,
/// The hash of a change (unambiguous prefixes are accepted)
let mut changes = Vec::new();
let hashes = if self.change_id.is_empty() {
// No change ids were given, present a list for choosing
// The number can be set in the global config or passed as a command-line option
let number_of_changes = if let Some(n) = self.show_changes {
n
} else {
let cfg = crate::config::Global::load()?;
cfg.unrecord_changes.ok_or_else(|| {
anyhow!(
"Can't determine how many changes to show. \
Please set the `unrecord_changes` option in \
your global config or run `pijul unrecord` \
with the `--show-changes` option."
)
})?
};
let hashes = txn
.reverse_log(&channel.borrow(), None)
.map(|(_, (h, _))| h)
.take(number_of_changes)
.collect::<Vec<_>>();
let o = make_changelist(&repo.changes, &hashes, "unrecord")?;
parse_changelist(&edit::edit_bytes(&o[..])?)
.iter()
.map(|h| h.to_base32())
.collect::<_>()
} else {
self.change_id
};
/// Make the "changelist", i.e. the list of patches, editable in a
/// text editor.
fn make_changelist<S: ChangeStore>(
changes: &S,
pullable: &[libpijul::Hash],
verb: &str,
) -> Result<Vec<u8>, anyhow::Error> {
use libpijul::Base32;
let mut v = Vec::new();
writeln!(
v,
"# Please select the changes to {}. The lines that contain just a
# valid hash, and no other character (except possibly a newline), will
# be {}ed.\n",
verb, verb,
)
.unwrap();
let mut first_p = true;
for p in pullable {
if !first_p {
writeln!(v).unwrap();
}
first_p = false;
writeln!(v, "{}\n", p.to_base32()).unwrap();
let deps = changes.get_dependencies(&p)?;
if !deps.is_empty() {
write!(v, " Dependencies:").unwrap();
for d in deps {
write!(v, " {}", d.to_base32()).unwrap();
}
writeln!(v).unwrap();
}
let change = changes.get_header(&p)?;
write!(v, " Author: [").unwrap();
let mut first = true;
for a in change.authors.iter() {
if !first {
write!(v, ", ").unwrap();
}
first = false;
write!(v, "{}", a).unwrap();
}
writeln!(v, "]").unwrap();
writeln!(v, " Date: {}\n", change.timestamp).unwrap();
for l in change.message.lines() {
writeln!(v, " {}", l).unwrap();
}
if let Some(desc) = change.description {
writeln!(v).unwrap();
for l in desc.lines() {
writeln!(v, " {}", l).unwrap();
}
}
}
Ok(v)
}
fn parse_changelist(o: &[u8]) -> Vec<libpijul::Hash> {
use libpijul::Base32;
if let Ok(o) = std::str::from_utf8(o) {
o.lines()
.filter_map(|l| libpijul::Hash::from_base32(l.as_bytes()))
.collect()
} else {
Vec::new()
}
}
/// Make a "changelist", i.e. a list of patches that can be edited in
/// a text editor.
fn make_changelist<S: libpijul::changestore::ChangeStore>(
changes: &S,
pullable: &[libpijul::Hash],
verb: &str,
) -> Result<Vec<u8>, anyhow::Error> {
use libpijul::Base32;
use std::io::Write;
let mut v = Vec::new();
// TODO: This message should probably be customizable
writeln!(
v,
"# Please select the changes to {}. The lines that contain just a
# valid hash, and no other character (except possibly a newline), will
# be {}ed.\n",
verb, verb,
)
.unwrap();
let mut first_p = true;
for p in pullable {
if !first_p {
writeln!(v, "").unwrap();
}
first_p = false;
writeln!(v, "{}\n", p.to_base32()).unwrap();
let deps = changes.get_dependencies(&p)?;
if !deps.is_empty() {
write!(v, " Dependencies:").unwrap();
for d in deps {
write!(v, " {}", d.to_base32()).unwrap();
}
writeln!(v).unwrap();
}
let change = changes.get_header(&p)?;
write!(v, " Author: [").unwrap();
let mut first = true;
for a in change.authors.iter() {
if !first {
write!(v, ", ").unwrap();
}
first = false;
write!(v, "{}", a).unwrap();
}
writeln!(v, "]").unwrap();
writeln!(v, " Date: {}\n", change.timestamp).unwrap();
for l in change.message.lines() {
writeln!(v, " {}", l).unwrap();
}
if let Some(desc) = change.description {
writeln!(v).unwrap();
for l in desc.lines() {
writeln!(v, " {}", l).unwrap();
}
}
}
Ok(v)
}
/// Parses a list of hashes from a slice of bytes.
/// Everything that is not a line consisting of a
/// valid hash and nothing else will be ignored.
fn parse_changelist(o: &[u8]) -> Vec<libpijul::Hash> {
use libpijul::Base32;
if let Ok(o) = std::str::from_utf8(o) {
o.lines()
.filter_map(|l| libpijul::Hash::from_base32(l.as_bytes()))
.collect()
} else {
Vec::new()
}
}