Compare commits
4 Commits
v1.0.0-bet
...
feat/trash
| Author | SHA1 | Date | |
|---|---|---|---|
| a81022bb0b | |||
| d36364d60d | |||
| 99363475e0 | |||
| a52e1877fe |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -21,3 +21,6 @@ dist/
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
# Added by goreleaser init:
|
# Added by goreleaser init:
|
||||||
.intentionally-empty-file.o
|
.intentionally-empty-file.o
|
||||||
|
|
||||||
|
.cargo/
|
||||||
|
vendor/
|
||||||
|
|||||||
637
Cargo.lock
generated
637
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
|||||||
use std::cmp::Reverse;
|
use std::cmp::Reverse;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{BTreeSet, HashMap, HashSet};
|
||||||
use std::hash::{DefaultHasher, Hash, Hasher};
|
use std::hash::{DefaultHasher, Hash, Hasher};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
@@ -55,7 +55,24 @@ enum Signal {
|
|||||||
/// Eose received from relay pool
|
/// Eose received from relay pool
|
||||||
Eose,
|
Eose,
|
||||||
/// An error occurred
|
/// An error occurred
|
||||||
Error(SharedString),
|
Error(FailedMessage),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Signal {
|
||||||
|
pub fn message(gift_wrap: EventId, rumor: UnsignedEvent) -> Self {
|
||||||
|
Self::Message(NewMessage::new(gift_wrap, rumor))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eose() -> Self {
|
||||||
|
Self::Eose
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn error<T>(event: &Event, reason: T) -> Self
|
||||||
|
where
|
||||||
|
T: Into<SharedString>,
|
||||||
|
{
|
||||||
|
Self::Error(FailedMessage::new(event, reason))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Chat Registry
|
/// Chat Registry
|
||||||
@@ -64,6 +81,9 @@ pub struct ChatRegistry {
|
|||||||
/// Chat rooms
|
/// Chat rooms
|
||||||
rooms: Vec<Entity<Room>>,
|
rooms: Vec<Entity<Room>>,
|
||||||
|
|
||||||
|
/// Events that failed to unwrap for any reason
|
||||||
|
trashes: Entity<BTreeSet<FailedMessage>>,
|
||||||
|
|
||||||
/// Tracking events seen on which relays in the current session
|
/// Tracking events seen on which relays in the current session
|
||||||
seens: Arc<RwLock<HashMap<EventId, HashSet<RelayUrl>>>>,
|
seens: Arc<RwLock<HashMap<EventId, HashSet<RelayUrl>>>>,
|
||||||
|
|
||||||
@@ -128,6 +148,7 @@ impl ChatRegistry {
|
|||||||
|
|
||||||
Self {
|
Self {
|
||||||
rooms: vec![],
|
rooms: vec![],
|
||||||
|
trashes: cx.new(|_| BTreeSet::default()),
|
||||||
seens: Arc::new(RwLock::new(HashMap::default())),
|
seens: Arc::new(RwLock::new(HashMap::default())),
|
||||||
tracking_flag: Arc::new(AtomicBool::new(false)),
|
tracking_flag: Arc::new(AtomicBool::new(false)),
|
||||||
signal_rx: rx,
|
signal_rx: rx,
|
||||||
@@ -144,6 +165,7 @@ impl ChatRegistry {
|
|||||||
let signer = nostr.read(cx).signer();
|
let signer = nostr.read(cx).signer();
|
||||||
let status = self.tracking_flag.clone();
|
let status = self.tracking_flag.clone();
|
||||||
let seens = self.seens.clone();
|
let seens = self.seens.clone();
|
||||||
|
let trashes = self.trashes.downgrade();
|
||||||
|
|
||||||
let initialized_at = Timestamp::now();
|
let initialized_at = Timestamp::now();
|
||||||
let sub_id1 = SubscriptionId::new(DEVICE_GIFTWRAP);
|
let sub_id1 = SubscriptionId::new(DEVICE_GIFTWRAP);
|
||||||
@@ -163,7 +185,7 @@ impl ChatRegistry {
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
match message {
|
match *message {
|
||||||
RelayMessage::Event { event, .. } => {
|
RelayMessage::Event { event, .. } => {
|
||||||
// Keep track of which relays have seen this event
|
// Keep track of which relays have seen this event
|
||||||
{
|
{
|
||||||
@@ -185,28 +207,30 @@ impl ChatRegistry {
|
|||||||
match extract_rumor(&client, &signer, event.as_ref()).await {
|
match extract_rumor(&client, &signer, event.as_ref()).await {
|
||||||
Ok(rumor) => {
|
Ok(rumor) => {
|
||||||
if rumor.tags.is_empty() {
|
if rumor.tags.is_empty() {
|
||||||
let error: SharedString = "No room for message".into();
|
let signal =
|
||||||
tx.send_async(Signal::Error(error)).await?;
|
Signal::error(event.as_ref(), "Recipient is missing");
|
||||||
|
tx.send_async(signal).await?;
|
||||||
|
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if rumor.created_at >= initialized_at {
|
if rumor.created_at >= initialized_at {
|
||||||
let new_message = NewMessage::new(event.id, rumor);
|
let signal = Signal::message(event.id, rumor);
|
||||||
let signal = Signal::Message(new_message);
|
|
||||||
|
|
||||||
tx.send_async(signal).await?;
|
tx.send_async(signal).await?;
|
||||||
} else {
|
} else {
|
||||||
status.store(true, Ordering::Release);
|
status.store(true, Ordering::Release);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let error: SharedString = format!("Failed to unwrap: {e}").into();
|
let reason = format!("Failed to extract rumor: {e}");
|
||||||
tx.send_async(Signal::Error(error)).await?;
|
let signal = Signal::error(event.as_ref(), reason);
|
||||||
|
tx.send_async(signal).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RelayMessage::EndOfStoredEvents(id) => {
|
RelayMessage::EndOfStoredEvents(id) => {
|
||||||
if id.as_ref() == &sub_id1 || id.as_ref() == &sub_id2 {
|
if id.as_ref() == &sub_id1 || id.as_ref() == &sub_id2 {
|
||||||
tx.send_async(Signal::Eose).await?;
|
tx.send_async(Signal::eose()).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -229,9 +253,10 @@ impl ChatRegistry {
|
|||||||
this.get_rooms(cx);
|
this.get_rooms(cx);
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
Signal::Error(error) => {
|
Signal::Error(trash) => {
|
||||||
this.update(cx, |_this, cx| {
|
trashes.update(cx, |this, cx| {
|
||||||
cx.emit(ChatEvent::Error(error));
|
this.insert(trash);
|
||||||
|
cx.notify();
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -685,8 +710,8 @@ async fn extract_rumor(
|
|||||||
gift_wrap: &Event,
|
gift_wrap: &Event,
|
||||||
) -> Result<UnsignedEvent, Error> {
|
) -> Result<UnsignedEvent, Error> {
|
||||||
// Try to get cached rumor first
|
// Try to get cached rumor first
|
||||||
if let Ok(event) = get_rumor(client, gift_wrap.id).await {
|
if let Ok(rumor) = get_rumor(client, gift_wrap.id).await {
|
||||||
return Ok(event);
|
return Ok(rumor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to unwrap with the available signer
|
// Try to unwrap with the available signer
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use std::hash::Hash;
|
|||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
use common::{EventUtils, NostrParser};
|
use common::{EventUtils, NostrParser};
|
||||||
|
use gpui::SharedString;
|
||||||
use nostr_sdk::prelude::*;
|
use nostr_sdk::prelude::*;
|
||||||
|
|
||||||
/// New message.
|
/// New message.
|
||||||
@@ -24,6 +25,25 @@ impl NewMessage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trash message.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct FailedMessage {
|
||||||
|
pub raw_event: String,
|
||||||
|
pub reason: SharedString,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FailedMessage {
|
||||||
|
pub fn new<T>(event: &Event, reason: T) -> Self
|
||||||
|
where
|
||||||
|
T: Into<SharedString>,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
raw_event: event.as_json(),
|
||||||
|
reason: reason.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Message.
|
/// Message.
|
||||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||||
pub enum Message {
|
pub enum Message {
|
||||||
|
|||||||
@@ -201,15 +201,12 @@ impl ChatPanel {
|
|||||||
let mut notifications = client.notifications();
|
let mut notifications = client.notifications();
|
||||||
|
|
||||||
while let Some(notification) = notifications.next().await {
|
while let Some(notification) = notifications.next().await {
|
||||||
if let ClientNotification::Message {
|
if let ClientNotification::Message { message, relay_url } = notification
|
||||||
message:
|
&& let RelayMessage::Ok {
|
||||||
RelayMessage::Ok {
|
event_id,
|
||||||
event_id,
|
status,
|
||||||
status,
|
message,
|
||||||
message,
|
} = *message
|
||||||
},
|
|
||||||
relay_url,
|
|
||||||
} = notification
|
|
||||||
{
|
{
|
||||||
let sent_ids = sent_ids.read().await;
|
let sent_ids = sent_ids.read().await;
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ fn main() {
|
|||||||
cx.set_menus(vec![Menu {
|
cx.set_menus(vec![Menu {
|
||||||
name: "Coop".into(),
|
name: "Coop".into(),
|
||||||
items: vec![MenuItem::action("Quit", Quit)],
|
items: vec![MenuItem::action("Quit", Quit)],
|
||||||
|
disabled: false,
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
// Set up the window bounds
|
// Set up the window bounds
|
||||||
|
|||||||
@@ -149,10 +149,8 @@ impl DeviceRegistry {
|
|||||||
let mut processed_events = HashSet::new();
|
let mut processed_events = HashSet::new();
|
||||||
|
|
||||||
while let Some(notification) = notifications.next().await {
|
while let Some(notification) = notifications.next().await {
|
||||||
if let ClientNotification::Message {
|
if let ClientNotification::Message { message, .. } = notification
|
||||||
message: RelayMessage::Event { event, .. },
|
&& let RelayMessage::Event { event, .. } = *message
|
||||||
..
|
|
||||||
} = notification
|
|
||||||
{
|
{
|
||||||
if !processed_events.insert(event.id) {
|
if !processed_events.insert(event.id) {
|
||||||
// Skip if the event has already been processed
|
// Skip if the event has already been processed
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ impl PersonRegistry {
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
if let RelayMessage::Event { event, .. } = message {
|
if let RelayMessage::Event { event, .. } = *message {
|
||||||
// Skip if the event has already been processed
|
// Skip if the event has already been processed
|
||||||
if !processed.insert(event.id) {
|
if !processed.insert(event.id) {
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ impl RelayAuth {
|
|||||||
|
|
||||||
while let Some(notification) = notifications.next().await {
|
while let Some(notification) = notifications.next().await {
|
||||||
if let ClientNotification::Message { relay_url, message } = notification {
|
if let ClientNotification::Message { relay_url, message } = notification {
|
||||||
match message {
|
match *message {
|
||||||
RelayMessage::Auth { challenge } => {
|
RelayMessage::Auth { challenge } => {
|
||||||
if challenges.insert(challenge.clone()) {
|
if challenges.insert(challenge.clone()) {
|
||||||
let request = Arc::new(AuthRequest::new(challenge, relay_url));
|
let request = Arc::new(AuthRequest::new(challenge, relay_url));
|
||||||
@@ -221,31 +221,31 @@ impl RelayAuth {
|
|||||||
|
|
||||||
while let Some(notification) = notifications.next().await {
|
while let Some(notification) = notifications.next().await {
|
||||||
match notification {
|
match notification {
|
||||||
RelayNotification::Message {
|
RelayNotification::Message { message } => {
|
||||||
message: RelayMessage::Ok { event_id, .. },
|
if let RelayMessage::Ok { event_id, .. } = *message {
|
||||||
} => {
|
if id != event_id {
|
||||||
if id != event_id {
|
continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get all subscriptions
|
|
||||||
let subscriptions = relay.subscriptions().await;
|
|
||||||
|
|
||||||
// Re-subscribe to previous subscriptions
|
|
||||||
for (id, filters) in subscriptions.into_iter() {
|
|
||||||
if !filters.is_empty() {
|
|
||||||
relay.send_msg(ClientMessage::req(id, filters)).await?;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Re-send pending events
|
// Get all subscriptions
|
||||||
for id in pending_events {
|
let subscriptions = relay.subscriptions().await;
|
||||||
if let Some(event) = client.database().event_by_id(&id).await? {
|
|
||||||
relay.send_event(&event).await?;
|
// Re-subscribe to previous subscriptions
|
||||||
|
for (id, filters) in subscriptions.into_iter() {
|
||||||
|
if !filters.is_empty() {
|
||||||
|
relay.send_msg(ClientMessage::req(id, filters)).await?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(());
|
// Re-send pending events
|
||||||
|
for id in pending_events {
|
||||||
|
if let Some(event) = client.database().event_by_id(&id).await? {
|
||||||
|
relay.send_event(&event).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
RelayNotification::AuthenticationFailed => break,
|
RelayNotification::AuthenticationFailed => break,
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|||||||
14
flathub/.gitignore
vendored
Normal file
14
flathub/.gitignore
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# Generated files - do not commit to main repo
|
||||||
|
# These are generated by prepare-flathub.sh
|
||||||
|
vendor/
|
||||||
|
vendor.tar.gz
|
||||||
|
su.reya.coop.yml
|
||||||
|
su.reya.coop.metainfo.xml
|
||||||
|
release-info.xml
|
||||||
|
cargo-config.toml
|
||||||
|
build/
|
||||||
|
repo/
|
||||||
|
|
||||||
|
# Keep the README and this .gitignore
|
||||||
|
!README.md
|
||||||
|
!.gitignore
|
||||||
129
flathub/README.md
Normal file
129
flathub/README.md
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
# Flathub Submission for Coop
|
||||||
|
|
||||||
|
This directory contains the files needed to submit Coop to Flathub.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Flatpak installed
|
||||||
|
- `flatpak-builder` installed
|
||||||
|
- Rust/Cargo installed (for vendoring)
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
Run the preparation script from the repo root:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./script/prepare-flathub.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
This will:
|
||||||
|
1. Vendor all Rust dependencies (crates.io + git)
|
||||||
|
2. Generate the metainfo.xml with proper release info
|
||||||
|
3. Create `su.reya.coop.yml` - the Flatpak manifest for Flathub
|
||||||
|
|
||||||
|
## Files Generated
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `su.reya.coop.yml` | Main Flatpak manifest (submit this to Flathub) |
|
||||||
|
| `su.reya.coop.metainfo.xml` | AppStream metadata with release info |
|
||||||
|
| `vendor.tar.gz` | Vendored Rust dependencies |
|
||||||
|
| `cargo-config.toml` | Cargo configuration for offline builds |
|
||||||
|
| `release-info.xml` | Release info snippet for metainfo |
|
||||||
|
|
||||||
|
## Testing Locally
|
||||||
|
|
||||||
|
Before submitting to Flathub, test the build:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd flathub
|
||||||
|
|
||||||
|
# Build and install locally
|
||||||
|
flatpak-builder --user --install --force-clean build su.reya.coop.yml
|
||||||
|
|
||||||
|
# Test the app
|
||||||
|
flatpak run su.reya.coop
|
||||||
|
|
||||||
|
# Run the Flathub linter (must pass!)
|
||||||
|
flatpak run --command=flatpak-builder-lint org.flatpak.Builder manifest su.reya.coop.yml
|
||||||
|
flatpak run --command=flatpak-builder-lint org.flatpak.Builder repo repo
|
||||||
|
```
|
||||||
|
|
||||||
|
## Submitting to Flathub
|
||||||
|
|
||||||
|
### 1. Prepare Your Release
|
||||||
|
|
||||||
|
Ensure you have:
|
||||||
|
- [ ] Committed all changes
|
||||||
|
- [ ] Tagged the release: `git tag -a v1.0.0-beta2 -m "Release v1.0.0-beta2"`
|
||||||
|
- [ ] Pushed the tag: `git push origin v1.0.0-beta2`
|
||||||
|
- [ ] Run `./script/prepare-flathub.sh` to regenerate files
|
||||||
|
|
||||||
|
### 2. Fork and Submit
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Fork https://github.com/flathub/flathub on GitHub first
|
||||||
|
|
||||||
|
# Clone your fork (use the new-pr branch!)
|
||||||
|
git clone --branch=new-pr git@github.com:YOUR_USERNAME/flathub.git
|
||||||
|
cd flathub
|
||||||
|
|
||||||
|
# Create a new branch
|
||||||
|
git checkout -b su.reya.coop
|
||||||
|
|
||||||
|
# Copy ONLY the manifest file from your project
|
||||||
|
cp /path/to/coop/flathub/su.reya.coop.yml .
|
||||||
|
|
||||||
|
# Commit and push
|
||||||
|
git add su.reya.coop.yml
|
||||||
|
git commit -m "Add su.reya.coop"
|
||||||
|
git push origin su.reya.coop
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Open Pull Request
|
||||||
|
|
||||||
|
1. Go to your fork on GitHub
|
||||||
|
2. Click "Compare & pull request"
|
||||||
|
3. **Important:** Set base branch to `new-pr` (not `master`!)
|
||||||
|
4. Fill in the PR template
|
||||||
|
5. Submit and wait for review
|
||||||
|
|
||||||
|
## What Happens Next?
|
||||||
|
|
||||||
|
1. Flathub's automated CI will build your app
|
||||||
|
2. A maintainer will review your submission
|
||||||
|
3. Once approved, a new repo `flathub/su.reya.coop` will be created
|
||||||
|
4. You'll get write access to maintain the app
|
||||||
|
5. Future updates: Push new commits to `flathub/su.reya.coop`
|
||||||
|
|
||||||
|
## Updating the App
|
||||||
|
|
||||||
|
To release a new version:
|
||||||
|
|
||||||
|
1. Update version in workspace `Cargo.toml`
|
||||||
|
2. Tag the new release: `git tag -a v1.0.0-beta3 -m "Release v1.0.0-beta3"`
|
||||||
|
3. Push the tag: `git push origin v1.0.0-beta3`
|
||||||
|
4. Run `./script/prepare-flathub.sh` to regenerate
|
||||||
|
5. Clone the flathub repo: `git clone https://github.com/flathub/su.reya.coop.git`
|
||||||
|
6. Update the manifest with new commit/tag and hashes
|
||||||
|
7. Submit PR to `flathub/su.reya.coop`
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Build fails with "network access not allowed"
|
||||||
|
- Make sure `CARGO_NET_OFFLINE=true` is set in the manifest
|
||||||
|
- Ensure `vendor.tar.gz` is properly extracted before building
|
||||||
|
|
||||||
|
### Linter complains about metainfo
|
||||||
|
- Ensure `su.reya.coop.metainfo.xml` has at least one `<release>` entry
|
||||||
|
- Check that screenshots are accessible URLs
|
||||||
|
|
||||||
|
### Missing dependencies
|
||||||
|
- If new git dependencies are added, re-run `prepare-flathub.sh`
|
||||||
|
- The script vendors all dependencies from `Cargo.lock`
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
- [Flathub Submission Docs](https://docs.flathub.org/docs/for-app-authors/submission)
|
||||||
|
- [Flatpak Manifest Reference](https://docs.flatpak.org/en/latest/manifests.html)
|
||||||
|
- [AppStream Metainfo Guide](https://www.freedesktop.org/software/appstream/docs/chap-Metadata.html)
|
||||||
245
script/prepare-flathub
Executable file
245
script/prepare-flathub
Executable file
@@ -0,0 +1,245 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Prepare Flathub submission for Coop
|
||||||
|
# This script:
|
||||||
|
# 1. Vendors all Rust dependencies (crates.io + git)
|
||||||
|
# 2. Generates release info for metainfo.xml
|
||||||
|
# 3. Creates the Flathub manifest (su.reya.coop.yml)
|
||||||
|
#
|
||||||
|
# Usage: ./script/prepare-flathub [--release-date YYYY-MM-DD]
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
APP_ID="su.reya.coop"
|
||||||
|
APP_NAME="Coop"
|
||||||
|
REPO_URL="https://git.reya.su/reya/coop"
|
||||||
|
BRANDING_LIGHT="#FFE629"
|
||||||
|
BRANDING_DARK="#FFE629"
|
||||||
|
|
||||||
|
# Parse arguments
|
||||||
|
RELEASE_DATE=""
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
--release-date)
|
||||||
|
RELEASE_DATE="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
echo "Usage: ${0##*/} [options]"
|
||||||
|
echo ""
|
||||||
|
echo "Options:"
|
||||||
|
echo " --release-date DATE Release date in YYYY-MM-DD format (default: today)"
|
||||||
|
echo " -h, --help Display this help and exit"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown option: $1" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Get version from workspace
|
||||||
|
VERSION=$(script/get-crate-version coop)
|
||||||
|
if [[ -z "$RELEASE_DATE" ]]; then
|
||||||
|
RELEASE_DATE=$(date +%Y-%m-%d)
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "=== Preparing Flathub submission for $APP_NAME v$VERSION ==="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Create flathub directory
|
||||||
|
mkdir -p flathub
|
||||||
|
echo "[1/5] Created flathub/ directory"
|
||||||
|
|
||||||
|
# Step 2: Vendor all dependencies
|
||||||
|
echo "[2/5] Vendoring Rust dependencies..."
|
||||||
|
if [[ -d vendor ]]; then
|
||||||
|
echo " Removing old vendor directory..."
|
||||||
|
rm -rf vendor
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create cargo config for vendoring
|
||||||
|
mkdir -p .cargo
|
||||||
|
cat > .cargo/config.toml << 'EOF'
|
||||||
|
[source.crates-io]
|
||||||
|
replace-with = "vendored"
|
||||||
|
|
||||||
|
[source.vendored]
|
||||||
|
directory = "vendor"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Vendor all dependencies (crates.io + git)
|
||||||
|
cargo vendor --locked vendor/
|
||||||
|
echo " Vendored dependencies to vendor/"
|
||||||
|
|
||||||
|
# Create tarball of vendored deps
|
||||||
|
tar -czf flathub/vendor.tar.gz vendor/
|
||||||
|
echo " Created flathub/vendor.tar.gz"
|
||||||
|
|
||||||
|
# Step 3: Generate release info for metainfo
|
||||||
|
echo "[3/5] Generating release info..."
|
||||||
|
cat > flathub/release-info.xml << EOF
|
||||||
|
<release version="${VERSION}" date="${RELEASE_DATE}">
|
||||||
|
<description>
|
||||||
|
<p>Release version ${VERSION}</p>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
|
EOF
|
||||||
|
echo " Created flathub/release-info.xml"
|
||||||
|
|
||||||
|
# Step 4: Generate the metainfo file with release info
|
||||||
|
echo "[4/5] Generating metainfo.xml..."
|
||||||
|
export APP_ID APP_NAME BRANDING_LIGHT BRANDING_DARK
|
||||||
|
cat crates/coop/resources/flatpak/coop.metainfo.xml.in | \
|
||||||
|
sed -e "/@release_info@/r flathub/release-info.xml" -e '/@release_info@/d' \
|
||||||
|
> flathub/${APP_ID}.metainfo.xml
|
||||||
|
echo " Created flathub/${APP_ID}.metainfo.xml"
|
||||||
|
|
||||||
|
# Step 5: Generate the Flatpak manifest
|
||||||
|
echo "[5/5] Generating Flatpak manifest..."
|
||||||
|
|
||||||
|
# Get current commit hash
|
||||||
|
COMMIT=$(git rev-parse HEAD)
|
||||||
|
|
||||||
|
# Generate the YAML manifest
|
||||||
|
cat > flathub/${APP_ID}.yml << 'MANIFEST_EOF'
|
||||||
|
id: su.reya.coop
|
||||||
|
runtime: org.freedesktop.Platform
|
||||||
|
runtime-version: "24.08"
|
||||||
|
sdk: org.freedesktop.Sdk
|
||||||
|
sdk-extensions:
|
||||||
|
- org.freedesktop.Sdk.Extension.rust-stable
|
||||||
|
- org.freedesktop.Sdk.Extension.llvm18
|
||||||
|
command: coop
|
||||||
|
finish-args:
|
||||||
|
- --talk-name=org.freedesktop.Flatpak
|
||||||
|
- --device=dri
|
||||||
|
- --share=ipc
|
||||||
|
- --share=network
|
||||||
|
- --socket=wayland
|
||||||
|
- --socket=fallback-x11
|
||||||
|
- --socket=pulseaudio
|
||||||
|
- --filesystem=host
|
||||||
|
|
||||||
|
build-options:
|
||||||
|
append-path: /usr/lib/sdk/rust-stable/bin:/usr/lib/sdk/llvm18/bin
|
||||||
|
env:
|
||||||
|
CC: clang
|
||||||
|
CXX: clang++
|
||||||
|
|
||||||
|
modules:
|
||||||
|
- name: coop
|
||||||
|
buildsystem: simple
|
||||||
|
build-options:
|
||||||
|
env:
|
||||||
|
CARGO_HOME: /run/build/coop/cargo
|
||||||
|
CARGO_NET_OFFLINE: "true"
|
||||||
|
RELEASE_VERSION: "@VERSION@"
|
||||||
|
build-commands:
|
||||||
|
# Setup vendored dependencies
|
||||||
|
- mkdir -p .cargo
|
||||||
|
- cp cargo-config.toml .cargo/config.toml
|
||||||
|
|
||||||
|
# Extract vendored deps
|
||||||
|
- tar -xzf vendor.tar.gz
|
||||||
|
|
||||||
|
# Build the project (entire workspace, then install coop binary)
|
||||||
|
- cargo build --release --offline --package coop
|
||||||
|
|
||||||
|
# Install binary
|
||||||
|
- install -Dm755 target/release/coop /app/bin/coop
|
||||||
|
|
||||||
|
# Install icons
|
||||||
|
- install -Dm644 crates/coop/resources/icon.png /app/share/icons/hicolor/512x512/apps/su.reya.coop.png
|
||||||
|
- install -Dm644 crates/coop/resources/icon@2x.png /app/share/icons/hicolor/1024x1024/apps/su.reya.coop.png
|
||||||
|
|
||||||
|
# Install desktop file
|
||||||
|
- |
|
||||||
|
export APP_ID="su.reya.coop"
|
||||||
|
export APP_ICON="su.reya.coop"
|
||||||
|
export APP_NAME="Coop"
|
||||||
|
export APP_CLI="coop"
|
||||||
|
export APP_ARGS="%U"
|
||||||
|
export DO_STARTUP_NOTIFY="true"
|
||||||
|
envsubst < crates/coop/resources/coop.desktop.in > coop.desktop
|
||||||
|
install -Dm644 coop.desktop /app/share/applications/su.reya.coop.desktop
|
||||||
|
|
||||||
|
# Install metainfo (use pre-generated one with release info)
|
||||||
|
- install -Dm644 su.reya.coop.metainfo.xml /app/share/metainfo/su.reya.coop.metainfo.xml
|
||||||
|
|
||||||
|
sources:
|
||||||
|
# Main source code - specific commit
|
||||||
|
- type: git
|
||||||
|
url: https://git.reya.su/reya/coop.git
|
||||||
|
commit: "@COMMIT@"
|
||||||
|
tag: "v@VERSION@"
|
||||||
|
|
||||||
|
# Vendored dependencies tarball (generated by this script)
|
||||||
|
- type: file
|
||||||
|
path: vendor.tar.gz
|
||||||
|
sha256: "@VENDOR_SHA256@"
|
||||||
|
|
||||||
|
# Pre-generated metainfo with release info
|
||||||
|
- type: file
|
||||||
|
path: su.reya.coop.metainfo.xml
|
||||||
|
sha256: "@METAINFO_SHA256@"
|
||||||
|
|
||||||
|
# Cargo config for vendoring
|
||||||
|
- type: file
|
||||||
|
path: cargo-config.toml
|
||||||
|
sha256: "@CARGO_CONFIG_SHA256@"
|
||||||
|
MANIFEST_EOF
|
||||||
|
|
||||||
|
# Calculate SHA256 hashes
|
||||||
|
VENDOR_SHA256=$(sha256sum flathub/vendor.tar.gz | cut -d' ' -f1)
|
||||||
|
METAINFO_SHA256=$(sha256sum flathub/${APP_ID}.metainfo.xml | cut -d' ' -f1)
|
||||||
|
|
||||||
|
# Create cargo-config.toml
|
||||||
|
mkdir -p flathub
|
||||||
|
cat > flathub/cargo-config.toml << 'EOF'
|
||||||
|
[source.crates-io]
|
||||||
|
replace-with = "vendored"
|
||||||
|
|
||||||
|
[source.vendored]
|
||||||
|
directory = "vendor"
|
||||||
|
EOF
|
||||||
|
CARGO_CONFIG_SHA256=$(sha256sum flathub/cargo-config.toml | cut -d' ' -f1)
|
||||||
|
|
||||||
|
# Substitute values into the manifest
|
||||||
|
sed -i \
|
||||||
|
-e "s/@VERSION@/${VERSION}/g" \
|
||||||
|
-e "s/@COMMIT@/${COMMIT}/g" \
|
||||||
|
-e "s/@VENDOR_SHA256@/${VENDOR_SHA256}/g" \
|
||||||
|
-e "s/@METAINFO_SHA256@/${METAINFO_SHA256}/g" \
|
||||||
|
-e "s/@CARGO_CONFIG_SHA256@/${CARGO_CONFIG_SHA256}/g" \
|
||||||
|
flathub/${APP_ID}.yml
|
||||||
|
|
||||||
|
echo " Created flathub/${APP_ID}.yml"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Flathub preparation complete! ==="
|
||||||
|
echo ""
|
||||||
|
echo "Files generated in flathub/:"
|
||||||
|
echo " - ${APP_ID}.yml # Main Flatpak manifest (submit this to Flathub)"
|
||||||
|
echo " - ${APP_ID}.metainfo.xml # AppStream metadata with release info"
|
||||||
|
echo " - vendor.tar.gz # Vendored Rust dependencies"
|
||||||
|
echo " - cargo-config.toml # Cargo configuration for vendoring"
|
||||||
|
echo " - release-info.xml # Release info snippet"
|
||||||
|
echo ""
|
||||||
|
echo "Next steps:"
|
||||||
|
echo " 1. Test the build locally:"
|
||||||
|
echo " cd flathub && flatpak-builder --user --install --force-clean build ${APP_ID}.yml"
|
||||||
|
echo ""
|
||||||
|
echo " 2. If build succeeds, submit to Flathub:"
|
||||||
|
echo " - Fork https://github.com/flathub/flathub"
|
||||||
|
echo " - Clone: git clone --branch=new-pr git@github.com:YOUR_USERNAME/flathub.git"
|
||||||
|
echo " - Copy ONLY ${APP_ID}.yml to the repo"
|
||||||
|
echo " - Submit PR against flathub/flathub:new-pr"
|
||||||
|
echo ""
|
||||||
|
echo "Note: Make sure you have:"
|
||||||
|
echo " - Committed all changes (commit: ${COMMIT})"
|
||||||
|
echo " - Tagged the release (tag: v${VERSION})"
|
||||||
|
echo " - Pushed the tag to GitHub"
|
||||||
Reference in New Issue
Block a user