diff --git a/backend/src/s9pk/builder.rs b/backend/src/s9pk/builder.rs index 28052a086..3a30d8efc 100644 --- a/backend/src/s9pk/builder.rs +++ b/backend/src/s9pk/builder.rs @@ -1,3 +1,4 @@ +use nom::combinator::success; use sha2_old::{Digest, Sha512}; use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt, SeekFrom}; use tracing::instrument; diff --git a/backend/src/s9pk/git_hash.rs b/backend/src/s9pk/git_hash.rs new file mode 100644 index 000000000..b2990a111 --- /dev/null +++ b/backend/src/s9pk/git_hash.rs @@ -0,0 +1,41 @@ +use std::path::Path; + +use crate::Error; + +#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] +pub struct GitHash(String); + +impl GitHash { + pub async fn from_path(path: impl AsRef) -> Result { + let hash = tokio::process::Command::new("git") + .args(["describe", "--always", "--abbrev=40", "--dirty=-modified"]) + .current_dir(path) + .output() + .await?; + if !hash.status.success() { + return Err(Error::new( + color_eyre::eyre::eyre!("Could not get hash: {}", String::from_utf8(hash.stderr)?), + crate::ErrorKind::Filesystem, + )); + } + Ok(GitHash(String::from_utf8(hash.stdout)?)) + } +} + +impl AsRef for GitHash { + fn as_ref(&self) -> &str { + &self.0 + } +} + +// #[tokio::test] +// async fn test_githash_for_current() { +// let answer: GitHash = GitHash::from_path(std::env::current_dir().unwrap()) +// .await +// .unwrap(); +// let answer_str: &str = answer.as_ref(); +// assert!( +// !answer_str.is_empty(), +// "Should have a hash for this current working" +// ); +// } diff --git a/backend/src/s9pk/manifest.rs b/backend/src/s9pk/manifest.rs index 311b4f2a0..d54700488 100644 --- a/backend/src/s9pk/manifest.rs +++ b/backend/src/s9pk/manifest.rs @@ -20,6 +20,8 @@ use crate::version::{Current, VersionT}; use crate::volume::Volumes; use crate::Error; +use super::git_hash::GitHash; + fn current_version() -> Version { Current::new().semver().into() } @@ -30,6 +32,8 @@ pub struct Manifest { #[serde(default = "current_version")] pub eos_version: Version, pub id: PackageId, + #[serde(default)] + pub git_hash: Option, pub title: String, #[model] pub version: Version, @@ -96,6 +100,11 @@ impl Manifest { .chain(migrations) .chain(actions) } + + pub fn with_git_hash(mut self, git_hash: GitHash) -> Self { + self.git_hash = Some(git_hash); + self + } } #[derive(Clone, Debug, Default, Deserialize, Serialize)] diff --git a/backend/src/s9pk/mod.rs b/backend/src/s9pk/mod.rs index 399ac0a7e..f0fcddc02 100644 --- a/backend/src/s9pk/mod.rs +++ b/backend/src/s9pk/mod.rs @@ -12,6 +12,7 @@ use tracing::instrument; use crate::context::SdkContext; use crate::s9pk::builder::S9pkPacker; use crate::s9pk::docker::DockerMultiArch; +use crate::s9pk::git_hash::GitHash; use crate::s9pk::manifest::Manifest; use crate::s9pk::reader::S9pkReader; use crate::util::display_none; @@ -22,6 +23,7 @@ use crate::{Error, ErrorKind, ResultExt}; pub mod builder; pub mod docker; +pub mod git_hash; pub mod header; pub mod manifest; pub mod reader; @@ -56,8 +58,10 @@ pub async fn pack(#[context] ctx: SdkContext, #[arg] path: Option) -> R crate::ErrorKind::Pack, )); }; - let manifest: Manifest = serde_json::from_value(manifest_value.clone()) - .with_kind(crate::ErrorKind::Deserialization)?; + + let manifest: Manifest = serde_json::from_value::(manifest_value.clone()) + .with_kind(crate::ErrorKind::Deserialization)? + .with_git_hash(GitHash::from_path(&path).await?); let extra_keys = enumerate_extra_keys(&serde_json::to_value(&manifest).unwrap(), &manifest_value); for k in extra_keys { diff --git a/frontend/projects/marketplace/package.json b/frontend/projects/marketplace/package.json index 787a4bda7..65e22086e 100644 --- a/frontend/projects/marketplace/package.json +++ b/frontend/projects/marketplace/package.json @@ -11,4 +11,4 @@ "dependencies": { "tslib": "^2.3.0" } -} +} \ No newline at end of file diff --git a/frontend/projects/marketplace/src/pages/show/additional/additional.component.html b/frontend/projects/marketplace/src/pages/show/additional/additional.component.html index b6ed8ee5b..da497709a 100644 --- a/frontend/projects/marketplace/src/pages/show/additional/additional.component.html +++ b/frontend/projects/marketplace/src/pages/show/additional/additional.component.html @@ -1,9 +1,16 @@ Additional Info - + - + + + +

Git Hash

+

{{ manifest['git-hash'] }}

+
+ +

Other Versions

@@ -14,7 +21,7 @@

Other Versions

License

-

{{ pkg.manifest.license }}

+

{{ manifest.license }}

@@ -31,41 +38,55 @@

Instructions

- +

Source Repository

-

{{ pkg.manifest['upstream-repo'] }}

+

{{ manifest['upstream-repo'] }}

Wrapper Repository

-

{{ pkg.manifest['wrapper-repo'] }}

+

{{ manifest['wrapper-repo'] }}

Support Site

-

{{ pkg.manifest['support-site'] }}

+

{{ manifest['support-site'] || 'Not provided' }}

+
+ +
+ + +

Marketing Site

+

{{ manifest['marketing-site'] || 'Not provided' }}

diff --git a/frontend/projects/marketplace/src/pages/show/additional/additional.component.ts b/frontend/projects/marketplace/src/pages/show/additional/additional.component.ts index 37c7efbbf..ba4c9d0d5 100644 --- a/frontend/projects/marketplace/src/pages/show/additional/additional.component.ts +++ b/frontend/projects/marketplace/src/pages/show/additional/additional.component.ts @@ -5,8 +5,17 @@ import { Input, Output, } from '@angular/core' -import { AlertController, ModalController } from '@ionic/angular' -import { displayEmver, Emver, MarkdownComponent } from '@start9labs/shared' +import { + AlertController, + ModalController, + ToastController, +} from '@ionic/angular' +import { + copyToClipboard, + displayEmver, + Emver, + MarkdownComponent, +} from '@start9labs/shared' import { MarketplacePkg } from '../../../types' import { AbstractMarketplaceService } from '../../../services/marketplace.service' @@ -27,8 +36,23 @@ export class AdditionalComponent { private readonly modalCtrl: ModalController, private readonly emver: Emver, private readonly marketplaceService: AbstractMarketplaceService, + private readonly toastCtrl: ToastController, ) {} + async copy(address: string): Promise { + const success = await copyToClipboard(address) + const message = success + ? 'Copied to clipboard!' + : 'Failed to copy to clipboard.' + + const toast = await this.toastCtrl.create({ + header: message, + position: 'bottom', + duration: 1000, + }) + await toast.present() + } + async presentAlertVersions() { const alert = await this.alertCtrl.create({ header: 'Versions', diff --git a/frontend/projects/marketplace/src/types.ts b/frontend/projects/marketplace/src/types.ts index a7072e507..cdcc3effd 100644 --- a/frontend/projects/marketplace/src/types.ts +++ b/frontend/projects/marketplace/src/types.ts @@ -36,6 +36,7 @@ export interface MarketplaceManifest { id: string title: string version: string + 'git-hash': string description: { short: string long: string diff --git a/frontend/projects/ui/src/app/pages/apps-routes/app-show/app-show.module.ts b/frontend/projects/ui/src/app/pages/apps-routes/app-show/app-show.module.ts index 6f6a2dcff..d338e9a81 100644 --- a/frontend/projects/ui/src/app/pages/apps-routes/app-show/app-show.module.ts +++ b/frontend/projects/ui/src/app/pages/apps-routes/app-show/app-show.module.ts @@ -14,6 +14,7 @@ import { AppShowStatusComponent } from './components/app-show-status/app-show-st import { AppShowDependenciesComponent } from './components/app-show-dependencies/app-show-dependencies.component' import { AppShowMenuComponent } from './components/app-show-menu/app-show-menu.component' import { AppShowHealthChecksComponent } from './components/app-show-health-checks/app-show-health-checks.component' +import { AppShowAdditionalComponent } from './components/app-show-additional/app-show-additional.component' import { HealthColorPipe } from './pipes/health-color.pipe' import { ToHealthChecksPipe } from './pipes/to-health-checks.pipe' import { ToButtonsPipe } from './pipes/to-buttons.pipe' @@ -43,6 +44,7 @@ const routes: Routes = [ AppShowDependenciesComponent, AppShowMenuComponent, AppShowHealthChecksComponent, + AppShowAdditionalComponent, ], imports: [ CommonModule, diff --git a/frontend/projects/ui/src/app/pages/apps-routes/app-show/app-show.page.html b/frontend/projects/ui/src/app/pages/apps-routes/app-show/app-show.page.html index 09797f608..0ee6288b3 100644 --- a/frontend/projects/ui/src/app/pages/apps-routes/app-show/app-show.page.html +++ b/frontend/projects/ui/src/app/pages/apps-routes/app-show/app-show.page.html @@ -23,6 +23,8 @@ > + +
diff --git a/frontend/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-additional/app-show-additional.component.html b/frontend/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-additional/app-show-additional.component.html new file mode 100644 index 000000000..e976e7467 --- /dev/null +++ b/frontend/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-additional/app-show-additional.component.html @@ -0,0 +1,72 @@ +Additional Info + + + + + + + +

Version

+

{{ manifest.version | displayEmver }}

+
+
+ + +

Git Hash

+

{{ manifest['git-hash'] }}

+
+ +
+ + +

License

+

{{ manifest.license }}

+
+ +
+
+
+ + + + +

Source Repository

+

{{ manifest['upstream-repo'] }}

+
+ +
+ + +

Wrapper Repository

+

{{ manifest['wrapper-repo'] }}

+
+ +
+ + +

Support Site

+

{{ manifest['support-site'] || 'Not provided' }}

+
+ +
+
+
+
+
+
diff --git a/frontend/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-additional/app-show-additional.component.ts b/frontend/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-additional/app-show-additional.component.ts new file mode 100644 index 000000000..501898428 --- /dev/null +++ b/frontend/projects/ui/src/app/pages/apps-routes/app-show/components/app-show-additional/app-show-additional.component.ts @@ -0,0 +1,48 @@ +import { ChangeDetectionStrategy, Component, Input } from '@angular/core' +import { ModalController, ToastController } from '@ionic/angular' +import { copyToClipboard, MarkdownComponent } from '@start9labs/shared' +import { from } from 'rxjs' +import { ApiService } from 'src/app/services/api/embassy-api.service' +import { PackageDataEntry } from 'src/app/services/patch-db/data-model' + +@Component({ + selector: 'app-show-additional', + templateUrl: 'app-show-additional.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AppShowAdditionalComponent { + @Input() + pkg!: PackageDataEntry + + constructor( + private readonly modalCtrl: ModalController, + private readonly toastCtrl: ToastController, + private readonly api: ApiService, + ) {} + + async copy(address: string): Promise { + const success = await copyToClipboard(address) + const message = success + ? 'Copied to clipboard!' + : 'Failed to copy to clipboard.' + + const toast = await this.toastCtrl.create({ + header: message, + position: 'bottom', + duration: 1000, + }) + await toast.present() + } + + async presentModalLicense() { + const modal = await this.modalCtrl.create({ + componentProps: { + title: 'License', + content: from(this.api.getStatic(this.pkg['static-files']['license'])), + }, + component: MarkdownComponent, + }) + + await modal.present() + } +} diff --git a/frontend/projects/ui/src/app/services/api/api.fixures.ts b/frontend/projects/ui/src/app/services/api/api.fixures.ts index fcfb159e5..60b93a2c1 100644 --- a/frontend/projects/ui/src/app/services/api/api.fixures.ts +++ b/frontend/projects/ui/src/app/services/api/api.fixures.ts @@ -42,6 +42,7 @@ export module Mock { id: 'bitcoind', title: 'Bitcoin Core', version: '0.21.0', + 'git-hash': 'abcdefgh', description: { short: 'A Bitcoin full node by Bitcoin Core.', long: 'Bitcoin is a decentralized consensus protocol and settlement network.', @@ -347,6 +348,7 @@ export module Mock { id: 'lnd', title: 'Lightning Network Daemon', version: '0.11.1', + 'git-hash': 'lalalalalala', description: { short: 'A bolt spec compliant client.', long: 'More info about LND. More info about LND. More info about LND.', @@ -500,6 +502,7 @@ export module Mock { id: 'btc-rpc-proxy', title: 'Bitcoin Proxy', version: '0.2.2', + 'git-hash': 'lmnopqrx', description: { short: 'A super charger for your Bitcoin node.', long: 'More info about Bitcoin Proxy. More info about Bitcoin Proxy. More info about Bitcoin Proxy.', diff --git a/frontend/projects/ui/src/app/services/api/mock-patch.ts b/frontend/projects/ui/src/app/services/api/mock-patch.ts index 787209751..327ab8104 100644 --- a/frontend/projects/ui/src/app/services/api/mock-patch.ts +++ b/frontend/projects/ui/src/app/services/api/mock-patch.ts @@ -61,6 +61,7 @@ export const mockPatchData: DataModel = { id: 'bitcoind', title: 'Bitcoin Core', version: '0.20.0', + 'git-hash': 'abcdefgh', description: { short: 'A Bitcoin full node by Bitcoin Core.', long: 'Bitcoin is a decentralized consensus protocol and settlement network.', @@ -452,6 +453,7 @@ export const mockPatchData: DataModel = { id: 'lnd', title: 'Lightning Network Daemon', version: '0.11.1', + 'git-hash': 'lalalalalala', description: { short: 'A bolt spec compliant client.', long: 'More info about LND. More info about LND. More info about LND.',