-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f6623ed
commit 503efc0
Showing
14 changed files
with
1,940 additions
and
45 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
.git | ||
target |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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), | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(()) | ||
} |
Oops, something went wrong.