Uploading all available versions
This commit is contained in:
+213
-106
@@ -1,19 +1,20 @@
|
|||||||
use clap::{Args, Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use dirs_next::config_dir;
|
use dirs_next::config_dir;
|
||||||
use reqwest::{Client, multipart};
|
use reqwest::{Client, multipart};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
use std::fmt::{Display, Formatter};
|
||||||
|
use std::fs;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{stdout, BufReader, BufWriter, Read, Write};
|
use std::io::{BufReader, BufWriter, Read, Write, stdout};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::string::ToString;
|
use std::string::ToString;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{fs, thread};
|
|
||||||
|
|
||||||
/// Nuget packages manager
|
/// Nuget packages manager
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug, Clone)]
|
||||||
#[command(version, about, long_about = None)]
|
#[command(version, about, long_about = None)]
|
||||||
struct CliArgs {
|
struct CliArgs {
|
||||||
/// Path to .nupkg file to send
|
/// Path to .nupkg file to send
|
||||||
@@ -30,7 +31,7 @@ struct CliArgs {
|
|||||||
command: Option<Commands>,
|
command: Option<Commands>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subcommand, Debug)]
|
#[derive(Subcommand, Debug, Clone)]
|
||||||
enum Commands {
|
enum Commands {
|
||||||
/// does testing things
|
/// does testing things
|
||||||
Test {
|
Test {
|
||||||
@@ -44,20 +45,25 @@ enum Commands {
|
|||||||
},
|
},
|
||||||
/// Forget personal nuget api key
|
/// Forget personal nuget api key
|
||||||
Logout,
|
Logout,
|
||||||
|
/// Show current configuration
|
||||||
ShowCfg,
|
ShowCfg,
|
||||||
|
/// Check newer packets versions
|
||||||
|
Check,
|
||||||
|
Publish,
|
||||||
}
|
}
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
struct Configuration {
|
struct Configuration {
|
||||||
key: Option<String>,
|
key: Option<String>,
|
||||||
packets: Vec<Packet>,
|
packets: Vec<Packet>,
|
||||||
}
|
}
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
struct Packet {
|
struct Packet {
|
||||||
key: String,
|
key: String,
|
||||||
version: Version,
|
version: Version,
|
||||||
path: String,
|
path: String,
|
||||||
}
|
}
|
||||||
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
|
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)]
|
||||||
struct Version {
|
struct Version {
|
||||||
major: u32,
|
major: u32,
|
||||||
minor: u32,
|
minor: u32,
|
||||||
@@ -79,7 +85,13 @@ impl Version {
|
|||||||
let c = u32::from_str(parts.pop().unwrap()).unwrap();
|
let c = u32::from_str(parts.pop().unwrap()).unwrap();
|
||||||
let b = u32::from_str(parts.pop().unwrap()).unwrap();
|
let b = u32::from_str(parts.pop().unwrap()).unwrap();
|
||||||
let a = u32::from_str(parts.pop().unwrap()).unwrap();
|
let a = u32::from_str(parts.pop().unwrap()).unwrap();
|
||||||
Version::new(c, b, a)
|
Version::new(a, b, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Version {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,7 +125,7 @@ impl Packet {
|
|||||||
let a = u32::from_str(parts.pop().unwrap()).unwrap();
|
let a = u32::from_str(parts.pop().unwrap()).unwrap();
|
||||||
|
|
||||||
let name = parts.join(".").to_string();
|
let name = parts.join(".").to_string();
|
||||||
println!("{}", name);
|
|
||||||
let dir = path.parent().unwrap().to_str().unwrap();
|
let dir = path.parent().unwrap().to_str().unwrap();
|
||||||
Packet {
|
Packet {
|
||||||
key: name,
|
key: name,
|
||||||
@@ -164,14 +176,15 @@ fn try_remember_packet(path: &Path, config: &mut Configuration) {
|
|||||||
{
|
{
|
||||||
Some(packet) => {
|
Some(packet) => {
|
||||||
let version = Version::from_name(&path.file_name().unwrap().to_str().unwrap());
|
let version = Version::from_name(&path.file_name().unwrap().to_str().unwrap());
|
||||||
if packet.version < version {
|
let more = packet.version < version;
|
||||||
|
if more {
|
||||||
packet.version = version;
|
packet.version = version;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => config.packets.push(Packet::new(path)),
|
None => config.packets.push(Packet::new(path)),
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{:?}", config)
|
write_config(config.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn conv(str: &mut String) {
|
fn conv(str: &mut String) {
|
||||||
@@ -179,100 +192,20 @@ fn conv(str: &mut String) {
|
|||||||
str.insert(0, last);
|
str.insert(0, last);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
async fn send_packet(path: &String, args: CliArgs) -> bool {
|
||||||
async fn main() {
|
let api_key: String;
|
||||||
let args = CliArgs::parse();
|
|
||||||
|
|
||||||
let config_folder = config_dir()
|
let config = &mut read_config();
|
||||||
.expect("Could not determine config directory")
|
|
||||||
.join("numan");
|
|
||||||
|
|
||||||
if !Path::exists(&config_folder) {
|
if let Some(key) = args.key {
|
||||||
fs::create_dir_all(&config_folder).unwrap()
|
api_key = key;
|
||||||
|
} else if let Some(key) = &config.key {
|
||||||
|
api_key = (*key).clone();
|
||||||
|
} else {
|
||||||
|
println!("Api key is not defined! Use -k [key]");
|
||||||
|
exit(4)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(path) = args.path {
|
|
||||||
let package = Path::new(&path);
|
|
||||||
if !package.exists() {
|
|
||||||
println!("File {} does not exist", path);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if !package.is_file() {
|
|
||||||
println!("{} is not a file", path);
|
|
||||||
exit(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !path.ends_with(".nupkg") {
|
|
||||||
println!("Invalid file: it is not nuget package");
|
|
||||||
exit(3);
|
|
||||||
}
|
|
||||||
|
|
||||||
let api_key: String;
|
|
||||||
|
|
||||||
let mut config = read_config();
|
|
||||||
|
|
||||||
if let Some(key) = args.key {
|
|
||||||
api_key = key;
|
|
||||||
} else if let Some(key) = &config.key {
|
|
||||||
api_key = (*key).clone();
|
|
||||||
} else {
|
|
||||||
println!("Api key is not defined! Use -k [key]");
|
|
||||||
exit(4)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
let success = send_packet(&path, api_key).await;
|
|
||||||
|
|
||||||
if !args.overlook && success{
|
|
||||||
try_remember_packet(&Path::new(&path), &mut config);
|
|
||||||
}
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
match &args.command {
|
|
||||||
Some(Commands::Test { list }) => {
|
|
||||||
if *list {
|
|
||||||
println!("Printing testing lists...");
|
|
||||||
} else {
|
|
||||||
println!("Not printing testing lists...");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(Commands::Auth { key }) => {
|
|
||||||
println!("Authenticating... {}", key);
|
|
||||||
let mut current = read_config();
|
|
||||||
|
|
||||||
current.key = Some(key.clone());
|
|
||||||
|
|
||||||
write_config(current);
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(Commands::ShowCfg) => {
|
|
||||||
let config = config_path();
|
|
||||||
|
|
||||||
let mut ctg = String::new();
|
|
||||||
|
|
||||||
match File::open(config) {
|
|
||||||
Ok(f) => {
|
|
||||||
let mut reader = BufReader::new(f);
|
|
||||||
reader.read_to_string(&mut ctg).unwrap();
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
ctg = "Not configured yet".to_string();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println!("{}", ctg);
|
|
||||||
}
|
|
||||||
Some(Commands::Logout) => {
|
|
||||||
let mut config = read_config();
|
|
||||||
config.key = None;
|
|
||||||
write_config(config);
|
|
||||||
}
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn send_packet(path: &String, api_key: String) -> bool {
|
|
||||||
let form = multipart::Form::new().file("", path.clone()).await.unwrap();
|
let form = multipart::Form::new().file("", path.clone()).await.unwrap();
|
||||||
let req_thread = tokio::spawn(async {
|
let req_thread = tokio::spawn(async {
|
||||||
let client = Client::new();
|
let client = Client::new();
|
||||||
@@ -287,7 +220,12 @@ async fn send_packet(path: &String, api_key: String) -> bool {
|
|||||||
});
|
});
|
||||||
let mut ind = "---->---->---->".to_string();
|
let mut ind = "---->---->---->".to_string();
|
||||||
|
|
||||||
print!("{} [{}] https://www.nuget.org/api/v2/package/{}", path, ind, "\x08".repeat(54));
|
print!(
|
||||||
|
"{} [{}] https://www.nuget.org/api/v2/package/{}",
|
||||||
|
path,
|
||||||
|
ind,
|
||||||
|
"\x08".repeat(54)
|
||||||
|
);
|
||||||
while !req_thread.is_finished() {
|
while !req_thread.is_finished() {
|
||||||
print!("{}", ind);
|
print!("{}", ind);
|
||||||
stdout().flush().unwrap();
|
stdout().flush().unwrap();
|
||||||
@@ -296,19 +234,188 @@ async fn send_packet(path: &String, api_key: String) -> bool {
|
|||||||
conv(&mut ind);
|
conv(&mut ind);
|
||||||
tokio::time::sleep(Duration::from_millis(100)).await;
|
tokio::time::sleep(Duration::from_millis(100)).await;
|
||||||
}
|
}
|
||||||
|
println!();
|
||||||
let response = req_thread.await.unwrap();
|
let response = req_thread.await.unwrap();
|
||||||
match response {
|
match response {
|
||||||
Ok(response) => {
|
Ok(response) => {
|
||||||
let status = response.status();
|
let status = response.status();
|
||||||
println!("Response: [{}] {:?}", status, response.text().await);
|
println!("Response: [{}] {}", status, response.text().await.unwrap());
|
||||||
if !status.is_success() {
|
if !status.is_success() {
|
||||||
return false;
|
// return false;
|
||||||
|
}
|
||||||
|
if !args.overlook {
|
||||||
|
try_remember_packet(&Path::new(&path), config);
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
println!("Error: {:?}", error.status().unwrap());
|
println!("Error: {:?}", error.status());
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
let args = CliArgs::parse();
|
||||||
|
let args_clone = args.clone();
|
||||||
|
let config_folder = config_dir()
|
||||||
|
.expect("Could not determine config directory")
|
||||||
|
.join("numan");
|
||||||
|
|
||||||
|
if !Path::exists(&config_folder) {
|
||||||
|
fs::create_dir_all(&config_folder).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(_) = args.path {
|
||||||
|
single_packet(args_clone).await;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match &args.command {
|
||||||
|
Some(Commands::Test { list }) => {
|
||||||
|
if *list {
|
||||||
|
println!("Printing testing lists...");
|
||||||
|
} else {
|
||||||
|
println!("Not printing testing lists...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(Commands::Auth { key }) => {
|
||||||
|
regular_key(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(Commands::ShowCfg) => {
|
||||||
|
show_config();
|
||||||
|
}
|
||||||
|
Some(Commands::Logout) => {
|
||||||
|
logout();
|
||||||
|
}
|
||||||
|
Some(Commands::Check) => check(),
|
||||||
|
Some(Commands::Publish) => {
|
||||||
|
publish(&args_clone).await;
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn publish(args: &CliArgs) {
|
||||||
|
println!("Publishing newer versions");
|
||||||
|
let config = read_config();
|
||||||
|
for packet in config.packets {
|
||||||
|
let path = packet.path;
|
||||||
|
print!("{} ({}) Current: [{}]", packet.key, path, packet.version);
|
||||||
|
let versions = find_packets(Path::new(&path));
|
||||||
|
if let Some(newer) = versions.iter().find(|v| v.version > packet.version) {
|
||||||
|
println!(" -> [{}]", newer.version);
|
||||||
|
println!("{:?}", newer);
|
||||||
|
send_packet(
|
||||||
|
&format!("{}/{}.{}.nupkg", newer.path, newer.key, newer.version),
|
||||||
|
args.clone(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
} else {
|
||||||
|
println!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn single_packet(args: CliArgs) {
|
||||||
|
let args_clone = args.clone();
|
||||||
|
let path = args_clone.clone().path.unwrap();
|
||||||
|
let package = Path::new(&path);
|
||||||
|
if !package.exists() {
|
||||||
|
println!("File {} does not exist", path);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if !package.is_file() {
|
||||||
|
println!("{} is not a file", path);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !path.ends_with(".nupkg") {
|
||||||
|
println!("Invalid file: it is not nuget package");
|
||||||
|
exit(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
send_packet(&path, args_clone).await;
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn regular_key(key: &String) {
|
||||||
|
println!("Authenticating... {}", key);
|
||||||
|
let mut current = read_config();
|
||||||
|
|
||||||
|
current.key = Some(key.clone());
|
||||||
|
|
||||||
|
write_config(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show_config() {
|
||||||
|
let config = config_path();
|
||||||
|
|
||||||
|
let mut ctg = String::new();
|
||||||
|
|
||||||
|
match File::open(config) {
|
||||||
|
Ok(f) => {
|
||||||
|
let mut reader = BufReader::new(f);
|
||||||
|
reader.read_to_string(&mut ctg).unwrap();
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
ctg = "Not configured yet".to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("{}", ctg);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn logout() {
|
||||||
|
let mut config = read_config();
|
||||||
|
config.key = None;
|
||||||
|
write_config(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_packets(path: &Path) -> Vec<Packet> {
|
||||||
|
let mut packets: Vec<Packet> = Vec::new();
|
||||||
|
|
||||||
|
for r in path.read_dir().unwrap() {
|
||||||
|
if let Ok(entry) = r {
|
||||||
|
if !entry.path().is_file() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let name = entry.file_name().to_str().unwrap().to_string();
|
||||||
|
if !name.ends_with(".nupkg") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
packets.push(Packet::new(entry.path().as_path()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
packets
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check() {
|
||||||
|
println!("Checking for newer versions");
|
||||||
|
let config = read_config();
|
||||||
|
println!("Found {} packets", config.packets.len());
|
||||||
|
let mut updates = 0_u32;
|
||||||
|
for packet in config.packets {
|
||||||
|
let path = packet.path;
|
||||||
|
print!("{} ({}) Current: [{}]", packet.key, path, packet.version);
|
||||||
|
let versions = find_packets(Path::new(&path));
|
||||||
|
if let Some(newer) = versions.iter().find(|v| v.version > packet.version) {
|
||||||
|
println!(" -> [{}]", newer.version);
|
||||||
|
updates += 1;
|
||||||
|
} else {
|
||||||
|
println!(" Lastest")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if updates > 0 {
|
||||||
|
println!("{} Updates found", updates);
|
||||||
|
}
|
||||||
|
if updates == 0 {
|
||||||
|
println!("No newer versions found.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user