.
This commit is contained in:
@@ -39,12 +39,7 @@ impl Assets {
|
||||
.filter_map(|path| {
|
||||
let data = Self::get(path.as_ref())?;
|
||||
let name = path.strip_prefix("themes/").unwrap_or(path.as_ref());
|
||||
let content = match data.data {
|
||||
std::borrow::Cow::Borrowed(bytes) => {
|
||||
std::str::from_utf8(bytes).ok()?.to_owned()
|
||||
}
|
||||
std::borrow::Cow::Owned(bytes) => String::from_utf8(bytes).ok()?,
|
||||
};
|
||||
let content = std::str::from_utf8(data.data.as_ref()).ok()?.to_owned();
|
||||
Some((name.to_owned(), content))
|
||||
})
|
||||
.collect()
|
||||
|
||||
@@ -19,8 +19,6 @@ pub struct InboxItem {
|
||||
pub root: EventId,
|
||||
/// The root event itself, when it is known locally.
|
||||
pub root_event: Option<Event>,
|
||||
/// Kind of the root event, when it is known locally.
|
||||
pub root_kind: Option<Kind>,
|
||||
/// Repository the root belongs to, from the root's `a` tag.
|
||||
pub address: Option<RepoAddr>,
|
||||
/// Notification events directed at the user, newest first.
|
||||
@@ -45,13 +43,11 @@ impl InboxItem {
|
||||
}
|
||||
|
||||
pub fn kind(&self) -> Option<Kind> {
|
||||
self.root_kind.or_else(|| {
|
||||
self.root_event
|
||||
.as_ref()
|
||||
.or_else(|| self.own_events.first())
|
||||
.or_else(|| self.events.first())
|
||||
.map(|event| event.kind)
|
||||
})
|
||||
self.root_event
|
||||
.as_ref()
|
||||
.or_else(|| self.own_events.first())
|
||||
.or_else(|| self.events.first())
|
||||
.map(|event| event.kind)
|
||||
}
|
||||
|
||||
/// Timestamp of the newest event in the thread.
|
||||
@@ -202,7 +198,6 @@ where
|
||||
|
||||
let mut item = InboxItem {
|
||||
root,
|
||||
root_kind: root_event.as_ref().map(|event| event.kind),
|
||||
address: root_event
|
||||
.as_ref()
|
||||
.and_then(|event| event.tags.coordinates().next()),
|
||||
|
||||
@@ -41,12 +41,10 @@ pub struct Upstream {
|
||||
/// Upstream repository coordinate when the `u` tag names a NIP-34 repository.
|
||||
/// `None` for the git-URL form.
|
||||
pub addr: Option<RepoAddr>,
|
||||
/// Relay hint for the upstream, if the `u` tag carries one.
|
||||
pub relay_hint: Option<RelayUrl>,
|
||||
}
|
||||
|
||||
impl Upstream {
|
||||
fn parse(raw: &str, relay_hint: Option<&str>) -> Self {
|
||||
fn parse(raw: &str) -> Self {
|
||||
let coordinate = raw.split('|').next().unwrap_or(raw);
|
||||
let addr = coordinate
|
||||
.parse::<Coordinate>()
|
||||
@@ -55,7 +53,6 @@ impl Upstream {
|
||||
Self {
|
||||
raw: raw.to_owned(),
|
||||
addr,
|
||||
relay_hint: relay_hint.and_then(|hint| RelayUrl::parse(hint).ok()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,7 +314,7 @@ impl Announcement {
|
||||
let values = tag.as_slice();
|
||||
let raw = values.get(1).map(String::as_str).unwrap_or_default();
|
||||
if !raw.is_empty() {
|
||||
upstream = Some(Upstream::parse(raw, values.get(2).map(String::as_str)));
|
||||
upstream = Some(Upstream::parse(raw));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -511,10 +508,6 @@ mod tests {
|
||||
upstream.raw,
|
||||
"30617:68d81165918100b7da43fc28f7d1fc12554466e1115886b9e7bb326f65ec4272:upstream|https://example.com/upstream.git"
|
||||
);
|
||||
assert_eq!(
|
||||
upstream.relay_hint,
|
||||
Some(RelayUrl::parse("wss://relay.example.com").expect("valid relay"))
|
||||
);
|
||||
assert_eq!(
|
||||
upstream.display().to_string(),
|
||||
"30617:68d81165918100b7da43fc28f7d1fc12554466e1115886b9e7bb326f65ec4272:upstream"
|
||||
|
||||
@@ -72,17 +72,6 @@ fn file_commit_with_description(
|
||||
})
|
||||
}
|
||||
|
||||
/// Find the most recent commit that changed `rel`, a path relative to the worktree.
|
||||
///
|
||||
/// `Ok(None)` when no commit touched the file, e.g. an untracked file.
|
||||
pub fn last_commit(repo: &gix::Repository, rel: &Path) -> Result<Option<FileCommit>> {
|
||||
let rel = rel.to_path_buf();
|
||||
Ok(last_commits(repo, std::slice::from_ref(&rel))?
|
||||
.into_iter()
|
||||
.next()
|
||||
.map(|(_, commit)| commit))
|
||||
}
|
||||
|
||||
/// Newest commit touching each of `rels`, like `git log -1 -- <rel>` per path.
|
||||
/// `rels` are paths relative to the worktree.
|
||||
///
|
||||
|
||||
@@ -16,8 +16,8 @@ pub use diff::{
|
||||
worktree_commit_range_diff,
|
||||
};
|
||||
pub use history::{
|
||||
CommitList, FileCommit, MAX_LISTED_COMMITS, all_commits, head_commit, last_commit,
|
||||
worktree_all_commits, worktree_commit, worktree_commit_range_commits, worktree_last_commits,
|
||||
CommitList, FileCommit, MAX_LISTED_COMMITS, all_commits, head_commit, worktree_all_commits,
|
||||
worktree_commit, worktree_commit_range_commits, worktree_last_commits,
|
||||
};
|
||||
pub use patch::{
|
||||
apply_patch, format_patch_between, patch_commits, patch_diffs, split_patch_series,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::{Context, Result, bail};
|
||||
use anyhow::{Context, Result};
|
||||
|
||||
use crate::history::open_with_cache;
|
||||
use crate::worktree::{force_checkout, worktree_dirty};
|
||||
@@ -171,12 +171,7 @@ pub fn init_repository(path: &Path, name: &str, description: &str) -> Result<Str
|
||||
let mut index = repo.index_from_tree(&tree)?;
|
||||
index.write(gix::index::write::Options::default())?;
|
||||
|
||||
let commit = commit.to_string();
|
||||
if commit.len() != 40 {
|
||||
bail!("unexpected initial commit id: {commit}");
|
||||
}
|
||||
|
||||
Ok(commit)
|
||||
Ok(commit.to_string())
|
||||
}
|
||||
|
||||
/// The earliest unique commit of the repository at `repo_path`.
|
||||
@@ -201,8 +196,7 @@ pub fn root_commit(repo_path: &Path) -> Result<Option<String>> {
|
||||
{
|
||||
let info = info?;
|
||||
if info.parent_ids().next().is_none() {
|
||||
let id = info.id().to_string();
|
||||
return Ok((id.len() == 40).then_some(id));
|
||||
return Ok(Some(info.id().to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
use super::*;
|
||||
@@ -578,7 +578,7 @@ fn git_run(dir: &Path, args: &[&str]) {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn last_commit_returns_most_recent_change() {
|
||||
fn worktree_last_commits_returns_most_recent_change() {
|
||||
let (dir, repo) = fixture(&[("a.txt", b"one")]);
|
||||
commit_all(&repo, "initial");
|
||||
|
||||
@@ -589,9 +589,12 @@ fn last_commit_returns_most_recent_change() {
|
||||
std::fs::write(dir.path().join("b.txt"), b"other").expect("write");
|
||||
commit_all(&repo, "add b");
|
||||
|
||||
let commit = last_commit(&repo, Path::new("a.txt"))
|
||||
let commit = worktree_last_commits(dir.path(), &[PathBuf::from("a.txt")])
|
||||
.expect("lookup")
|
||||
.expect("found");
|
||||
.into_iter()
|
||||
.next()
|
||||
.expect("found")
|
||||
.1;
|
||||
assert_eq!(commit.summary, "change a");
|
||||
assert_eq!(commit.author, "Test Author");
|
||||
assert!(!commit.id.is_empty());
|
||||
@@ -621,7 +624,7 @@ fn all_commits_lists_every_commit() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn last_commit_reports_merge_commits() {
|
||||
fn worktree_last_commits_reports_merge_commits() {
|
||||
let (dir, repo) = fixture(&[("a.txt", b"base")]);
|
||||
commit_all(&repo, "initial");
|
||||
|
||||
@@ -645,9 +648,12 @@ fn last_commit_reports_merge_commits() {
|
||||
// `--no-ff` forces a merge commit, it is the latest commit changing a.txt.
|
||||
run(&["merge", "--no-ff", "--no-edit", "feature"]);
|
||||
|
||||
let commit = last_commit(&repo, Path::new("a.txt"))
|
||||
let commit = worktree_last_commits(dir.path(), &[PathBuf::from("a.txt")])
|
||||
.expect("lookup")
|
||||
.expect("found");
|
||||
.into_iter()
|
||||
.next()
|
||||
.expect("found")
|
||||
.1;
|
||||
assert_eq!(
|
||||
commit.id,
|
||||
repo.head_id().expect("head").shorten_or_id().to_string()
|
||||
|
||||
@@ -64,20 +64,10 @@ pub fn worktree_commits_ahead(workdir: &Path, base: &str, branch: &str) -> u32 {
|
||||
walk.filter_map(Result::ok).count().min(u32::MAX as usize) as u32
|
||||
}
|
||||
|
||||
/// Resolve `rev` to a commit id, accepting full refs,
|
||||
/// symbolic refs and the bare branch names callers pass, like git's DWIM.
|
||||
/// Resolve `rev` to a commit id, accepting full refs or the bare branch names
|
||||
/// callers pass. `gix`'s revision parser already applies git's ref DWIM.
|
||||
fn resolve_commit<'a>(repo: &'a gix::Repository, rev: &str) -> Option<gix::Id<'a>> {
|
||||
if let Ok(id) = repo.rev_parse_single(rev.as_bytes()) {
|
||||
return Some(id);
|
||||
}
|
||||
|
||||
// Branch names arrive bare, like git resolving `main`.
|
||||
if rev.contains('/') {
|
||||
return None;
|
||||
}
|
||||
|
||||
repo.rev_parse_single(format!("refs/heads/{rev}").as_bytes())
|
||||
.ok()
|
||||
repo.rev_parse_single(rev.as_bytes()).ok()
|
||||
}
|
||||
|
||||
/// Relative paths of all entries in the worktree, files and directories.
|
||||
|
||||
@@ -5,32 +5,9 @@ use std::pin::Pin;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use nostr_connect::client::AuthUrlHandler;
|
||||
use nostr_sdk::error::Error as SignerError;
|
||||
use nostr_sdk::prelude::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UniversalSignerError(Box<dyn Error + Send + Sync + 'static>);
|
||||
|
||||
impl fmt::Display for UniversalSignerError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for UniversalSignerError {
|
||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
Some(&*self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl UniversalSignerError {
|
||||
pub fn new<E>(err: E) -> Self
|
||||
where
|
||||
E: Error + Send + Sync + 'static,
|
||||
{
|
||||
UniversalSignerError(Box::new(err))
|
||||
}
|
||||
}
|
||||
|
||||
/// A type-erased signer whose inner signer can be swapped in-place.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct UniversalSigner {
|
||||
@@ -65,21 +42,21 @@ impl UniversalSigner {
|
||||
trait InnerSigner: fmt::Debug + Send + Sync + 'static {
|
||||
fn get_public_key_async(
|
||||
&self,
|
||||
) -> Pin<Box<dyn Future<Output = Result<PublicKey, UniversalSignerError>> + Send + '_>>;
|
||||
) -> Pin<Box<dyn Future<Output = Result<PublicKey, SignerError>> + Send + '_>>;
|
||||
fn sign_event_async(
|
||||
&self,
|
||||
unsigned: UnsignedEvent,
|
||||
) -> Pin<Box<dyn Future<Output = Result<Event, UniversalSignerError>> + Send + '_>>;
|
||||
) -> Pin<Box<dyn Future<Output = Result<Event, SignerError>> + Send + '_>>;
|
||||
fn nip44_encrypt_async<'a>(
|
||||
&'a self,
|
||||
public_key: &'a PublicKey,
|
||||
content: &'a str,
|
||||
) -> Pin<Box<dyn Future<Output = Result<String, UniversalSignerError>> + Send + 'a>>;
|
||||
) -> Pin<Box<dyn Future<Output = Result<String, SignerError>> + Send + 'a>>;
|
||||
fn nip44_decrypt_async<'a>(
|
||||
&'a self,
|
||||
public_key: &'a PublicKey,
|
||||
payload: &'a str,
|
||||
) -> Pin<Box<dyn Future<Output = Result<String, UniversalSignerError>> + Send + 'a>>;
|
||||
) -> Pin<Box<dyn Future<Output = Result<String, SignerError>> + Send + 'a>>;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -94,22 +71,22 @@ where
|
||||
{
|
||||
fn get_public_key_async(
|
||||
&self,
|
||||
) -> Pin<Box<dyn Future<Output = Result<PublicKey, UniversalSignerError>> + Send + '_>> {
|
||||
) -> Pin<Box<dyn Future<Output = Result<PublicKey, SignerError>> + Send + '_>> {
|
||||
Box::pin(async move {
|
||||
AsyncGetPublicKey::get_public_key_async(&self.0)
|
||||
.await
|
||||
.map_err(UniversalSignerError::new)
|
||||
.map_err(SignerError::other)
|
||||
})
|
||||
}
|
||||
|
||||
fn sign_event_async(
|
||||
&self,
|
||||
unsigned: UnsignedEvent,
|
||||
) -> Pin<Box<dyn Future<Output = Result<Event, UniversalSignerError>> + Send + '_>> {
|
||||
) -> Pin<Box<dyn Future<Output = Result<Event, SignerError>> + Send + '_>> {
|
||||
Box::pin(async move {
|
||||
AsyncSignEvent::sign_event_async(&self.0, unsigned)
|
||||
.await
|
||||
.map_err(UniversalSignerError::new)
|
||||
.map_err(SignerError::other)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -117,11 +94,11 @@ where
|
||||
&'a self,
|
||||
public_key: &'a PublicKey,
|
||||
content: &'a str,
|
||||
) -> Pin<Box<dyn Future<Output = Result<String, UniversalSignerError>> + Send + 'a>> {
|
||||
) -> Pin<Box<dyn Future<Output = Result<String, SignerError>> + Send + 'a>> {
|
||||
Box::pin(async move {
|
||||
AsyncNip44::nip44_encrypt_async(&self.0, public_key, content)
|
||||
.await
|
||||
.map_err(UniversalSignerError::new)
|
||||
.map_err(SignerError::other)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -129,17 +106,17 @@ where
|
||||
&'a self,
|
||||
public_key: &'a PublicKey,
|
||||
payload: &'a str,
|
||||
) -> Pin<Box<dyn Future<Output = Result<String, UniversalSignerError>> + Send + 'a>> {
|
||||
) -> Pin<Box<dyn Future<Output = Result<String, SignerError>> + Send + 'a>> {
|
||||
Box::pin(async move {
|
||||
AsyncNip44::nip44_decrypt_async(&self.0, public_key, payload)
|
||||
.await
|
||||
.map_err(UniversalSignerError::new)
|
||||
.map_err(SignerError::other)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncGetPublicKey for UniversalSigner {
|
||||
type Error = UniversalSignerError;
|
||||
type Error = SignerError;
|
||||
|
||||
fn get_public_key_async(
|
||||
&self,
|
||||
@@ -150,7 +127,7 @@ impl AsyncGetPublicKey for UniversalSigner {
|
||||
}
|
||||
|
||||
impl AsyncSignEvent for UniversalSigner {
|
||||
type Error = UniversalSignerError;
|
||||
type Error = SignerError;
|
||||
|
||||
fn sign_event_async(
|
||||
&self,
|
||||
@@ -162,7 +139,7 @@ impl AsyncSignEvent for UniversalSigner {
|
||||
}
|
||||
|
||||
impl AsyncNip44 for UniversalSigner {
|
||||
type Error = UniversalSignerError;
|
||||
type Error = SignerError;
|
||||
|
||||
fn nip44_encrypt_async<'a>(
|
||||
&'a self,
|
||||
|
||||
@@ -1490,24 +1490,21 @@ const GRASP_RETRY_DELAY: Duration = Duration::from_secs(1);
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GraspServerResult {
|
||||
pub relay: RelayUrl,
|
||||
pub git_url: String,
|
||||
/// `None` when the server accepted the data, the reason otherwise.
|
||||
pub reason: Option<String>,
|
||||
}
|
||||
|
||||
impl GraspServerResult {
|
||||
fn ok(relay: RelayUrl, git_url: String) -> Self {
|
||||
fn ok(relay: RelayUrl) -> Self {
|
||||
Self {
|
||||
relay,
|
||||
git_url,
|
||||
reason: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn failed(relay: RelayUrl, git_url: String, reason: impl Into<String>) -> Self {
|
||||
fn failed(relay: RelayUrl, reason: impl Into<String>) -> Self {
|
||||
Self {
|
||||
relay,
|
||||
git_url,
|
||||
reason: Some(reason.into()),
|
||||
}
|
||||
}
|
||||
@@ -1709,11 +1706,9 @@ async fn push_staged_to_grasps(
|
||||
|
||||
for relay in servers {
|
||||
let Some(base) = grasp_base_url(relay) else {
|
||||
outcome.servers.push(GraspServerResult::failed(
|
||||
relay.clone(),
|
||||
relay.to_string(),
|
||||
"no domain",
|
||||
));
|
||||
outcome
|
||||
.servers
|
||||
.push(GraspServerResult::failed(relay.clone(), "no domain"));
|
||||
continue;
|
||||
};
|
||||
let git_url = format!("{base}/{owner}/{repo_id}.git");
|
||||
@@ -1794,11 +1789,9 @@ async fn push_staged_to_grasps(
|
||||
log::warn!("grasp push failed: {relay}: {reason}");
|
||||
outcome
|
||||
.servers
|
||||
.push(GraspServerResult::failed(relay.clone(), git_url, reason));
|
||||
.push(GraspServerResult::failed(relay.clone(), reason));
|
||||
}
|
||||
None => outcome
|
||||
.servers
|
||||
.push(GraspServerResult::ok(relay.clone(), git_url)),
|
||||
None => outcome.servers.push(GraspServerResult::ok(relay.clone())),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1956,13 +1949,9 @@ mod tests {
|
||||
fn push_outcome_reports_partial_failures() {
|
||||
let outcome = PushOutcome {
|
||||
servers: vec![
|
||||
GraspServerResult::ok(
|
||||
RelayUrl::parse("wss://gitnostr.com").expect("url"),
|
||||
"https://gitnostr.com/npub1owner/repo.git".to_owned(),
|
||||
),
|
||||
GraspServerResult::ok(RelayUrl::parse("wss://gitnostr.com").expect("url")),
|
||||
GraspServerResult::failed(
|
||||
RelayUrl::parse("wss://relay.ngit.dev").expect("url"),
|
||||
"https://relay.ngit.dev/npub1owner/repo.git".to_owned(),
|
||||
"remote: ERR authorisation failed: No state events in purgatory\nfatal: ...",
|
||||
),
|
||||
],
|
||||
|
||||
@@ -403,7 +403,7 @@ impl InboxView {
|
||||
};
|
||||
|
||||
let root = item.root;
|
||||
let kind = item.root_kind;
|
||||
let kind = item.root_event.as_ref().map(|event| event.kind);
|
||||
let address = section.address.clone();
|
||||
let first = entry_ix == 0;
|
||||
let last = entry_ix + 1 == section.entries.len();
|
||||
|
||||
Reference in New Issue
Block a user