Skip to content

Commit

Permalink
Our squashed release! Yay!
Browse files Browse the repository at this point in the history
  • Loading branch information
ejiektpobehuk committed Apr 6, 2021
1 parent f6623ed commit 503efc0
Show file tree
Hide file tree
Showing 14 changed files with 1,940 additions and 45 deletions.
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.git
target
18 changes: 16 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
[package]
name = "pacops"
description = "Automation around PACMAN, the package manager"
version = "0.1.0"
description = "PKGBUILD maintainer Swiss Army knife"
version = "0.0.1"
authors = ["Vlad Petrov <[email protected]>"]
edition = "2018"
licence = "GPL-3.0-or-later"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
clap = "2.33.3"
reqwest = { version = "0.11", features = ["blocking", "json"] }
version-compare = "0.0.11"
select = "0.5.0"
regex = "1.4.3"
blake2 = "0.9.1"
sha-1 = "0.9.3"
sha2 = "0.9.3"
md-5 = "0.9.1"
tempfile = "3.2.0"
shellexpand = "2.1"
serde = { version = "1.0", features = ["derive"] }
toml = "0.5"
dirs = "3.0"
17 changes: 17 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
FROM rust:1.51 as builder

WORKDIR /usr/src/pacops
COPY . .
RUN cargo build --release
RUN strip target/release/pacops

FROM archlinux:base-devel
LABEL version 0.0.1
LABEL description "PacOps Archlinux based build image"

RUN useradd --create-home --home-dir /usr/share/pacops pacops && echo -e 'Cmnd_Alias PACMAN=/usr/sbin/pacman *\npacops ALL= NOPASSWD: PACMAN' > /etc/sudoers.d/88_pacops

USER pacops
WORKDIR /usr/share/pacops
COPY --from=builder /usr/src/pacops/target/release/pacops /usr/bin/
ENTRYPOINT ["/usr/bin/pacops"]
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

49 changes: 49 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
**Warning:** This is an extremely early version.
We're just testing ideas.
Implementation might change completely.

**PacOps** is a package maintainers Swiss Army knife.
It's not an AUR helper, but it's made to help you maintain PKGBUILD files.

# General Goals:

* Upstream updates check
* Applying update to a PKGBUILD file
* Availability as GitHub Action
* AUR package maintenance (generate `.SRCINFO`, commit, subtree or regular push)
* Repo maintenance (build, sign, add to a repo db, upload)

# Install

Should be available as

* AUR package
* binary package in ejiek's repo
* Cargo package
* Docker image

## Docker usage

PacOps docker image is based on archlinux:base-devel and uses itself as a build environment.

```
docker run -v ${PWD}:/usr/share/pacops pacops ${path_to_a_PKGBUILD}
```

Git variables:
`GIT_AUTHOR_NAME`
`GIT_AUTHOR_EMAIL`

Makepkg variables:
`PACKAGER="John Doe <[email protected]>"`

# Roadmap

* Migrate of dummy parsing to [NomCup](https://github.com/ejiek/nomcup)
* GitHub as an upstream:
* releases
* tags
* branches
* Rootless containers (currently we don't have a workflow for rootless podman)
* Clean chroot life cycle (create, update, delete)
* Navigate user through repo creation
158 changes: 158 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
use serde::Deserialize;
extern crate dirs;

use std::error::Error;
use std::fs;
use std::path::PathBuf;
use std::rc::Rc;

// Layered config
#[derive(Clone, Deserialize, Debug)]
pub struct Config {
build: Option<Build>,
chroot: Option<PathBuf>,
commit: Option<bool>,
commit_message: Option<String>,
#[serde(skip_deserializing)]
parent: Option<Rc<Config>>,
srcinfo: Option<bool>,
}

impl Config {
pub fn defaults() -> Config {
Config {
build: Some(Build::Local),
chroot: None, // Look for one in XDG_something
commit: Some(false),
commit_message: Some(String::from("${pkgname}: ${old_version} -> ${new_version}")),
parent: None,
srcinfo: Some(false),
}
}
pub fn global_config_lookup() -> Result<Config, Box<dyn Error>> {
if let Some(mut config_file) = dirs::config_dir() {
config_file.push("pacops.toml");
return Config::read_from_file(config_file);
}

let error: Box<dyn std::error::Error> =
String::from("Unable locate configuration directory").into();
return Err(error);
}

pub fn read_from_file(path: PathBuf) -> Result<Config, Box<dyn Error>> {
let contents = fs::read_to_string(path)?;

let decoded: Config = toml::from_str(&contents)?;
return Ok(decoded);
}

pub fn set_parent_rc(&mut self, parent: Rc<Config>) {
self.parent = Some(parent);
}

pub fn set_chroot(&mut self, chroot: PathBuf) {
self.chroot = Some(chroot);
}

pub fn set_commit(&mut self, commit: bool) {
self.commit = Some(commit);
}

pub fn set_srcinfo(&mut self, srcinfo: bool) {
self.srcinfo = Some(srcinfo);
}

// Look into dedup of get functions
pub fn chroot(&self) -> Option<PathBuf> {
if let Some(actual_chroot) = self.chroot.clone() {
return Some(actual_chroot);
}
if let Some(actual_parent) = self.parent.clone() {
return actual_parent.chroot();
}
None
}

pub fn commit(&self) -> Option<bool> {
if let Some(actual_commit) = self.commit.clone() {
return Some(actual_commit);
}
if let Some(actual_parent) = self.parent.clone() {
return actual_parent.commit();
}
None
}

pub fn commit_message(&self) -> Option<String> {
if let Some(actual_commit_message) = self.commit_message.clone() {
return Some(actual_commit_message);
}
if let Some(actual_parent) = self.parent.clone() {
return actual_parent.commit_message();
}
None
}

pub fn build_type(&self) -> Option<Build> {
if let Some(actual_build) = self.build.clone() {
return Some(actual_build);
}
if let Some(actual_parent) = self.parent.clone() {
return actual_parent.build_type();
}
None
}

pub fn srcinfo(&self) -> Option<bool> {
if let Some(actual_srcinfo) = self.srcinfo.clone() {
return Some(actual_srcinfo);
}
if let Some(actual_parent) = self.parent.clone() {
return actual_parent.srcinfo();
}
None
}
}

impl PartialEq for Config {
fn eq(&self, other: &Self) -> bool {
self.build
.as_ref()
.unwrap()
.eq(&other.build.as_ref().unwrap())
&& self.chroot == other.chroot
&& self.commit_message == other.commit_message
}
}

#[derive(Clone, Deserialize, PartialEq, Debug)]
pub enum Build {
Local,
Chroot,
Docker,
Podman,
}

#[cfg(test)]
mod config_tests {
use super::*;

#[test]
fn test_config_parsing() {
let config_string = r#"build = 'Chroot'
chroot = '~/hobby/chroot/root'"#;

let decoded: Config = toml::from_str(config_string).unwrap();

let created = Config {
build: Some(Build::Chroot),
chroot: Some(PathBuf::from("~/hobby/chroot/root")),
commit: None,
commit_message: None,
parent: None,
srcinfo: Some(false),
};
assert_eq!(decoded, created);
}
}
87 changes: 87 additions & 0 deletions src/context.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
use std::cell::RefCell;
use std::error::Error;
use std::path::PathBuf;
use std::rc::Rc;

use crate::config::Config;
use crate::pkgbuild::Pkgbuild;
use crate::update::Update;

// context for working with a particular PKGBUILD
pub struct Context {
config: Rc<Config>,
pkgbuild: Option<Rc<RefCell<Pkgbuild>>>,
pkgbuild_path: Option<PathBuf>,
pkgname: Option<String>,
current_version: String,
update: Option<Update>,
}

impl Context {
pub fn new(config: Rc<Config>) -> Context {
Context {
config: config,
pkgbuild: None,
pkgbuild_path: None,
update: None,
pkgname: None,
current_version: String::from(""),
}
}

pub fn set_config(mut self, config: Rc<Config>) -> Self {
self.config = config;
self
}

pub fn set_pkgbuild(mut self, pkgbuild: Rc<RefCell<Pkgbuild>>) -> Self {
self.pkgbuild = Some(pkgbuild);
self
}

pub fn set_pkgbuild_path(mut self, path: PathBuf) -> Self {
self.pkgbuild_path = Some(path);
self
}

pub fn set_update(mut self, update: &Update) -> Self {
self.update = Some(update.clone());
self
}

pub fn set_current_version(mut self, current_version: String) -> Self {
self.current_version = current_version;
self
}

pub fn set_pkgname(mut self, pkgname: String) -> Self {
self.pkgname = Some(pkgname);
self
}

pub fn config(&self) -> Rc<Config> {
self.config.clone()
}

pub fn pkgbuild(&self) -> Option<Rc<RefCell<Pkgbuild>>> {
self.pkgbuild.clone()
}

pub fn pkgbuild_path(&self) -> Option<PathBuf> {
self.pkgbuild_path.clone()
}

pub fn shellexpand_context(&self) -> Box<dyn Fn(&str) -> Result<Option<String>, String>> {
let update = self.update.clone().unwrap();
let current_version = self.current_version.clone();
let pkgname = self.pkgname.clone();
Box::new(move |s| match s {
"pkgname" => Ok(Some(pkgname.as_ref().unwrap().clone())),
"old_version" => {
Ok(Some(current_version.clone())) // too many clones
}
"new_version" => Ok(Some(update.version.clone())),
_ => Ok(None),
})
}
}
43 changes: 43 additions & 0 deletions src/git.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use crate::context::Context;
use std::error::Error;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::str;

pub fn repo_root(path: &Path) -> Result<PathBuf, Box<dyn Error>> {
let git = Command::new("git")
.current_dir(path.to_str().unwrap())
.arg("rev-parse")
.arg("--show-toplevel")
.output()
.expect("failed to execute process");
println!("{}", str::from_utf8(&git.stderr).unwrap());
let repo_path = PathBuf::from(str::from_utf8(&git.stdout).unwrap());

//file.write_all(stdout)?;
Ok(repo_path)
}

pub fn commit(context: &Context) -> Result<(), Box<dyn Error>> {
let message_template = context.config().commit_message().unwrap();
let pkgbuild_path = context.pkgbuild_path().unwrap();
let path = pkgbuild_path.parent().unwrap();
let message = shellexpand::env_with_context(&message_template, &context.shellexpand_context())
.unwrap()
.into_owned();

// check if staging is empty
// add PKGBUILD & .SRCINFO if needed
let git = Command::new("git")
.current_dir(path.to_str().unwrap())
.arg("commit")
.arg("-m")
.arg(message)
.arg("PKGBUILD")
.arg(".SRCINFO")
.output()
.expect("failed to execute process");
println!("{}", str::from_utf8(&git.stdout).unwrap());
println!("{}", str::from_utf8(&git.stderr).unwrap());
Ok(())
}
Loading

0 comments on commit 503efc0

Please sign in to comment.