+30
-7
@@ -6,11 +6,21 @@ mod remove;
|
||||
|
||||
use clap::Parser;
|
||||
use rust_i18n::t;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
rust_i18n::i18n!("../locales/packie-cli");
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
enum Cli {
|
||||
struct Cli {
|
||||
#[arg(long)]
|
||||
chroot: Option<PathBuf>,
|
||||
|
||||
#[command(subcommand)]
|
||||
subcommand: Subcommand,
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
enum Subcommand {
|
||||
/// Get package information
|
||||
Info(info::Cli),
|
||||
|
||||
@@ -34,15 +44,28 @@ fn main() {
|
||||
});
|
||||
|
||||
let cli = Cli::parse();
|
||||
let result = match cli {
|
||||
Cli::Info(cli) => info::main(cli),
|
||||
Cli::InitDb(cli) => initdb::main(cli),
|
||||
Cli::Install(cli) => install::main(cli),
|
||||
Cli::Print(cli) => print::main(cli),
|
||||
Cli::Remove(cli) => remove::main(cli),
|
||||
if let Some(new_root) = cli.chroot
|
||||
&& let Err(err) = chroot(&new_root)
|
||||
{
|
||||
eprintln!("{}", t!("main.error", error = err));
|
||||
std::process::exit(1);
|
||||
}
|
||||
let result = match cli.subcommand {
|
||||
Subcommand::Info(cli) => info::main(cli),
|
||||
Subcommand::InitDb(cli) => initdb::main(cli),
|
||||
Subcommand::Install(cli) => install::main(cli),
|
||||
Subcommand::Print(cli) => print::main(cli),
|
||||
Subcommand::Remove(cli) => remove::main(cli),
|
||||
};
|
||||
if let Err(err) = result {
|
||||
eprintln!("{}", t!("main.error", error = err));
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
fn chroot(new_root: &Path) -> std::io::Result<()> {
|
||||
std::os::unix::fs::chroot(new_root)?;
|
||||
std::env::set_current_dir("/")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+1
-1
@@ -162,7 +162,7 @@ fn copy_fs_node(src: &Path, dst: &Path) -> std::io::Result<()> {
|
||||
}
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
fn symlink(src: &Path, dst: &Path) -> std::io::Result<()> {
|
||||
pub fn symlink(src: &Path, dst: &Path) -> std::io::Result<()> {
|
||||
std::os::unix::fs::symlink(src, dst)
|
||||
}
|
||||
|
||||
|
||||
+9
-1
@@ -57,7 +57,7 @@ pub fn install_package(
|
||||
|
||||
// Record installation in the database
|
||||
let installation = Installation {
|
||||
pkg_manifest,
|
||||
pkg_manifest: pkg_manifest.clone(),
|
||||
install_pkgspec,
|
||||
install_date: crate::common::timestamp_secs(),
|
||||
update_date: crate::common::timestamp_secs(),
|
||||
@@ -68,6 +68,14 @@ pub fn install_package(
|
||||
.insert_installation(&installation)
|
||||
.map_err(InstallError::Database)?;
|
||||
|
||||
// Enable default links
|
||||
for link in pkg_manifest.links.iter() {
|
||||
if !link.default {
|
||||
continue;
|
||||
}
|
||||
_ = crate::link::activate_by_description(packie, &pkg_manifest.pkg_ident(), link);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
+44
-9
@@ -1,4 +1,6 @@
|
||||
use crate::{Packie, package::PkgIdent};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
/// Description of a link.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
@@ -14,15 +16,48 @@ pub struct LinkDescription {
|
||||
pub default: bool,
|
||||
}
|
||||
|
||||
/// Status of a link in an installed package.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LinkStatus {
|
||||
/// Absolute path of the link source.
|
||||
pub from: String,
|
||||
pub fn activate_by_description(
|
||||
packie: &mut Packie,
|
||||
pkg_ident: &PkgIdent,
|
||||
description: &LinkDescription,
|
||||
) -> std::io::Result<()> {
|
||||
let bundle_path = packie.profile.pkg_dir.join(pkg_ident.to_string());
|
||||
let from = bundle_path.join(&description.from);
|
||||
create(from, &description.to)
|
||||
}
|
||||
|
||||
/// Absolute path of the link destination.
|
||||
pub to: String,
|
||||
pub fn deactivate_by_description(
|
||||
packie: &mut Packie,
|
||||
pkg_ident: &PkgIdent,
|
||||
description: &LinkDescription,
|
||||
) -> std::io::Result<()> {
|
||||
let bundle_path = packie.profile.pkg_dir.join(pkg_ident.to_string());
|
||||
let from = bundle_path.join(&description.from);
|
||||
let link_from = std::fs::read_link(&description.to)?;
|
||||
if link_from != from {
|
||||
return Err(std::io::ErrorKind::InvalidData.into());
|
||||
}
|
||||
remove(&description.to)
|
||||
}
|
||||
|
||||
/// True if the link is activated.
|
||||
pub activated: bool,
|
||||
pub fn create(from: impl AsRef<Path>, to: impl AsRef<Path>) -> std::io::Result<()> {
|
||||
std::fs::create_dir_all(
|
||||
to.as_ref()
|
||||
.parent()
|
||||
.ok_or_else(|| std::io::ErrorKind::InvalidInput)?,
|
||||
)?;
|
||||
crate::common::symlink(from.as_ref(), to.as_ref())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove(path: impl Into<PathBuf>) -> std::io::Result<()> {
|
||||
let mut path = path.into();
|
||||
if !std::fs::metadata(&path)?.is_symlink() {
|
||||
return Err(std::io::ErrorKind::InvalidData.into());
|
||||
}
|
||||
std::fs::remove_file(&path)?;
|
||||
while path.pop() {
|
||||
_ = std::fs::remove_dir(&path)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+9
-2
@@ -3,8 +3,6 @@ use rusqlite::{OpenFlags, Row, params};
|
||||
use std::path::Path;
|
||||
|
||||
/// Schema of the database.
|
||||
///
|
||||
/// The "installation" table records installed packages.
|
||||
const SCHEMA: &str = r#"
|
||||
CREATE TABLE IF NOT EXISTS "installation"(
|
||||
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
@@ -76,6 +74,15 @@ impl LocalDb {
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
pub fn select_installation_unique(
|
||||
&mut self,
|
||||
pkg_ident: &PkgIdent,
|
||||
) -> rusqlite::Result<Installation> {
|
||||
self.0.prepare_cached(r#"
|
||||
SELECT * FROM "installation" WHERE "pkg_name" = ?1 AND "pkg_version" = ?2 AND "pkg_arch" = ?3
|
||||
"#)?.query_one(params![pkg_ident.name, pkg_ident.version.to_string(), pkg_ident.arch], map_installation)
|
||||
}
|
||||
|
||||
pub fn remove_installation(&mut self, pkg_ident: &PkgIdent) -> rusqlite::Result<bool> {
|
||||
self
|
||||
.0
|
||||
|
||||
@@ -14,6 +14,11 @@ pub fn remove(packie: &mut Packie, pkgspec: &PkgSpec) -> Result<(), RemoveError>
|
||||
assert_eq!(found.len(), 1);
|
||||
let found = found.remove(0);
|
||||
|
||||
// Remove all links
|
||||
for link in found.pkg_manifest.links.iter() {
|
||||
_ = crate::link::deactivate_by_description(packie, &found.pkg_manifest.pkg_ident(), link);
|
||||
}
|
||||
|
||||
// Remove package files
|
||||
let bundle_dir = packie
|
||||
.profile
|
||||
|
||||
Reference in New Issue
Block a user