Skip to content

Commit

Permalink
Merge pull request #117 from a-kenji/feat/semver-update
Browse files Browse the repository at this point in the history
feat: add semver update functionality
  • Loading branch information
a-kenji authored Jul 20, 2024
2 parents 6118a88 + 5df3e12 commit dbdf8ce
Show file tree
Hide file tree
Showing 41 changed files with 1,401 additions and 43 deletions.
750 changes: 746 additions & 4 deletions Cargo.lock

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ homepage = "https://github.com/a-kenji/flake-add"
include = ["src/**/*", "LICENSE", "README.md", "build.rs"]

[[bin]]
name = "fe"
name = "flake-edit"

[workspace.package]
version = "0.1.0"
Expand Down Expand Up @@ -51,9 +51,11 @@ clap = { version = "4.5.7", optional = true, features = ["derive"] }
color-eyre = "0.6.3"
diffy = { version = "0.4.0", optional = true }
directories = "5.0.1"
nix-uri = "0.1.5"
nix-uri = "0.1.8"
reqwest = { version = "0.12.5", features = ["blocking"] }
rnix = "0.11.0"
ropey = { version = "1.6.1", optional = true }
semver = "1.0.23"
serde = "1.0.204"
serde_json = { version = "1.0.120", optional = true }
thiserror = "1.0.61"
Expand Down
2 changes: 1 addition & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::io::Write;
use std::path::PathBuf;
use std::{env, fs::create_dir_all, path::Path};

include!("src/bin/fe/cli.rs");
include!("src/bin/flake-edit/cli.rs");

fn main() {
println!("cargo:rerun-if-env-changed=ASSET_DIR");
Expand Down
25 changes: 13 additions & 12 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
rust-overlay.url = "github:oxalica/rust-overlay";
rust-overlay.inputs.nixpkgs.follows = "nixpkgs";
flake-parts.url = "github:hercules-ci/flake-parts";
crane.url = "github:ipetkov/crane";
crane.url = "github:ipetkov/crane?ref=v0.16.0";
crane.inputs.nixpkgs.follows = "nixpkgs";
treefmt-nix.url = "github:numtide/treefmt-nix/";
treefmt-nix.url = "github:numtide/treefmt-nix";
treefmt-nix.inputs.nixpkgs.follows = "nixpkgs";
};

Expand Down
10 changes: 7 additions & 3 deletions nix/fe.nix
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
self,
rustPlatform,
installShellFiles,
lib,
pkgs,

installShellFiles,
openssl,
pkg-config,
}:
let
cargoTOML = builtins.fromTOML (builtins.readFile (self + "/Cargo.toml"));
Expand All @@ -17,6 +17,10 @@ let
# crane
craneLib = self.inputs.crane.mkLib pkgs;
commonArgs = {
nativeBuildInputs = [
pkg-config
openssl
];
inherit version name;
pname = name;
src = lib.cleanSourceWith { src = craneLib.path ../.; };
Expand Down
140 changes: 140 additions & 0 deletions src/api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
use std::collections::HashMap;
use std::process::Command;

use reqwest::blocking::Client;
use reqwest::header::{HeaderMap, HeaderValue, USER_AGENT};
use semver::Version;
use serde::Deserialize;

#[derive(Deserialize, Debug)]
pub struct IntermediaryTags(Vec<IntermediaryTag>);

#[derive(Debug)]
pub struct Tags {
versions: Vec<Version>,
prefix: String,
}

impl Tags {
pub fn get_latest_tag(&mut self) -> String {
self.sort();
let mut buf = String::new();
buf.push_str(&self.prefix);
buf.push_str(&self.versions.iter().last().unwrap().to_string());
buf
}
pub fn sort(&mut self) {
self.versions.sort_by(Version::cmp_precedence);
}
}

#[derive(Deserialize, Debug)]
pub struct IntermediaryTag {
name: String,
}

pub fn get_tags(repo: &str, owner: &str) -> Result<Tags, ()> {
let tags = query_tags(repo, owner).unwrap();
Ok(tags.into())
}

#[derive(Deserialize, Debug, Clone)]
struct NixConfig {
#[serde(rename = "access-tokens")]
access_tokens: Option<AccessTokens>,
}

impl NixConfig {
fn gh_token(&self) -> Option<String> {
self.access_tokens
.clone()
.unwrap()
.value
.get("github.com")
.cloned()
}
}

#[derive(Deserialize, Debug, Clone)]
struct AccessTokens {
value: HashMap<String, String>,
}

// Try to query gh access tokens
pub fn get_gh_token() -> Option<String> {
let command = Command::new("nix")
.arg("config")
.arg("show")
.arg("--json")
.output()
.unwrap();
let stdout = String::from_utf8(command.stdout).unwrap();
let output: NixConfig = serde_json::from_str(&stdout).unwrap();

if let Some(token) = output.gh_token() {
return Some(token);
};
if let Ok(token) = std::env::var("GITHUB_TOKEN") {
return Some(token);
};

None
}

// https://api.github.com/repos/{OWNER}/{REPO}/tags
// Query tags for
fn query_tags(repo: &str, owner: &str) -> Result<IntermediaryTags, ()> {
let client = Client::new();
let mut headers = HeaderMap::new();
headers.insert(USER_AGENT, HeaderValue::from_str("flake-edit").unwrap());
if let Some(token) = get_gh_token() {
tracing::debug!("Found github token.");
headers.insert("authorization: Bearer", HeaderValue::from_str(&token).unwrap());
tracing::debug!("Settings github token.");
}
let body = client
.get(format!(
"https://api.github.com/repos/{}/{}/tags",
repo, owner
))
.headers(headers)
.send()
.unwrap()
.text()
.unwrap();

tracing::debug!("Body from api: {body}");

match serde_json::from_str::<IntermediaryTags>(&body) {
Ok(tags) => Ok(tags),
Err(e) => {
tracing::error!("Error from api: {e}");
Err(())
}
}
}

impl From<IntermediaryTags> for Tags {
fn from(value: IntermediaryTags) -> Self {
let mut versions = vec![];
let mut prefix = String::new();
for itag in value.0 {
let mut tag = itag.name;
// TODO: implement a generic way to find the version prefixes
if let Some(new_tag) = tag.strip_prefix('v') {
tag = new_tag.to_string();
prefix = "v".to_string();
}

match Version::parse(&tag) {
Ok(semver) => {
versions.push(semver);
}
Err(e) => {
tracing::error!("Could not parse version {:?}", e);
}
}
}
Tags { versions, prefix }
}
}
File renamed without changes.
File renamed without changes.
6 changes: 6 additions & 0 deletions src/bin/fe/cli.rs → src/bin/flake-edit/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ impl CliArgs {
pub(crate) fn list(&self) -> bool {
matches!(self.subcommand, Command::List { .. })
}
pub(crate) fn update(&self) -> bool {
matches!(self.subcommand, Command::Update { .. })
}

pub fn flake(&self) -> Option<&String> {
self.flake.as_ref()
Expand Down Expand Up @@ -104,6 +107,9 @@ pub(crate) enum Command {
#[arg(long, default_value_t = ListFormat::default())]
format: ListFormat,
},
/// Update inputs to their latest specified release.
#[clap(alias = "u")]
Update {},
#[clap(hide = true)]
#[command(name = "completion")]
/// Meant for shell completions.
Expand Down
File renamed without changes.
File renamed without changes.
41 changes: 39 additions & 2 deletions src/bin/fe/main.rs → src/bin/flake-edit/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use flake_edit::change::Change;
use flake_edit::diff::Diff;
use flake_edit::edit;
use flake_edit::input::Follows;
use flake_edit::input::Input;
use flake_edit::update::Updater;
use nix_uri::urls::UrlWrapper;
use nix_uri::{FlakeRef, NixUriResult};
use rnix::tokenizer::Tokenizer;
Expand Down Expand Up @@ -93,6 +95,7 @@ fn main() -> eyre::Result<()> {
};
}
}
cli::Command::Update { .. } => {}
cli::Command::List { .. } => {}
cli::Command::Change { id, uri } => {
if let Some(id) = id {
Expand All @@ -117,6 +120,17 @@ fn main() -> eyre::Result<()> {
std::process::exit(0);
}
},
Command::Add {
id,
uri,
ref_or_rev,
force,
no_flake,
} => todo!(),
Command::Pin { id } => todo!(),
Command::Change { id, uri } => todo!(),
Command::Remove { id } => todo!(),
Command::Completion { inputs, mode } => todo!(),
}

if let Ok(Some(resulting_change)) = editor.apply_change(change.clone()) {
Expand Down Expand Up @@ -145,15 +159,15 @@ fn main() -> eyre::Result<()> {
}

if args.diff() {
let old = text;
let old = text.clone();
let new = resulting_change;
let diff = Diff::new(&old, &new);
diff.compare();
// Write the changes
} else if args.apply() {
app.root.apply(&resulting_change)?;
}
} else if !args.list() {
} else if !args.list() && !args.update() {
if change.is_remove() {
return Err(eyre::eyre!(
"The input with id: {} could not be removed.",
Expand Down Expand Up @@ -230,5 +244,28 @@ fn main() -> eyre::Result<()> {
}
}
}
if let Command::Update {} = args.subcommand() {
let inputs = editor.list();
let mut buf = String::new();
flake_edit::api::get_gh_token();
for input in inputs.values() {
if !buf.is_empty() {
buf.push('\n');
}
buf.push_str(input.id());
}
let mut updater = Updater::new(app.root().text().clone(), inputs.clone());
updater.update();
let change = updater.get_changes();
if args.diff() {
let old = text.clone();
let new = change;
let diff = Diff::new(&old, &new);
diff.compare();
// Write the changes
} else if args.apply() {
app.root.apply(&change)?;
}
}
Ok(())
}
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit dbdf8ce

Please sign in to comment.