wip
This commit is contained in:
parent
f41157cab9
commit
840feb4df6
41
.drone.yml
41
.drone.yml
|
@ -1,41 +0,0 @@
|
|||
name: default
|
||||
kind: pipeline
|
||||
type: docker
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: rust:1
|
||||
commands:
|
||||
- cargo run -- --help
|
||||
|
||||
- name: deploy:crate
|
||||
image: rust:1
|
||||
environment:
|
||||
CARGO_REGISTRY_TOKEN:
|
||||
from_secret: CARGO_REGISTRY_TOKEN
|
||||
commands:
|
||||
- cargo publish
|
||||
when:
|
||||
event:
|
||||
include:
|
||||
- tag
|
||||
depends_on:
|
||||
- build
|
||||
|
||||
- name: deploy:wheel
|
||||
image: rust:1
|
||||
environment:
|
||||
MATURIN_URL:
|
||||
from_secret: MATURIN_URL
|
||||
MATURIN_USERNAME:
|
||||
from_secret: MATURIN_USERNAME
|
||||
MATURIN_PASSWORD:
|
||||
from_secret: MATURIN_PASSWORD
|
||||
commands:
|
||||
- maturin publish
|
||||
when:
|
||||
event:
|
||||
include:
|
||||
- tag
|
||||
depends_on:
|
||||
- build
|
|
@ -0,0 +1,31 @@
|
|||
name: Deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
|
||||
jobs:
|
||||
deploy-crate:
|
||||
runs-on: debian-rust
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Publish crate
|
||||
run: cargo publish
|
||||
|
||||
deploy-wheel:
|
||||
runs-on: debian-rust
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Publish wheel
|
||||
env:
|
||||
MATURIN_REPOSITORY_URL: ${{ secrets.PIP_REPOSITORY }}
|
||||
MATURIN_USERNAME: datahearth
|
||||
MATURIN_PYPI_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
||||
run: |
|
||||
pip install maturin
|
||||
maturin publish
|
|
@ -0,0 +1,22 @@
|
|||
name: Rust
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "main"
|
||||
pull_request:
|
||||
branches:
|
||||
- "main"
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: debian-rust
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Run tests
|
||||
run: cargo test --verbose
|
|
@ -1,2 +1 @@
|
|||
/target
|
||||
/my_project
|
||||
target
|
File diff suppressed because it is too large
Load Diff
|
@ -14,5 +14,6 @@ anyhow = "1.0"
|
|||
clap = { version = "4.0", features = ["derive"] }
|
||||
dialoguer = "0.10"
|
||||
regex = "1.7"
|
||||
reqwest = { version = "0.11", features = ["blocking", "json"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
toml = "0.5"
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
# pynit
|
||||
|
||||
[![License](https://img.shields.io/crates/l/pynit)](https://gitea.antoine-langlois.net/DataHearth/pynit/src/branch/main/LICENSE)
|
||||
[![Build Status](https://drone.antoine-langlois.net/api/badges/DataHearth/pynit/status.svg?ref=refs/heads/main)](https://drone.antoine-langlois.net/DataHearth/pynit)
|
||||
[![Build Status](https://img.shields.io/crates/v/pynit)](https://crates.io/crates/pynit)
|
||||
[![Version](https://img.shields.io/crates/v/pynit)](https://crates.io/crates/pynit)
|
||||
|
||||
---
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
#[macro_export]
|
||||
macro_rules! input {
|
||||
($theme:expr, $prompt:expr, $empty:expr) => {{
|
||||
Input::<String>::with_theme($theme)
|
||||
.with_prompt($prompt)
|
||||
.allow_empty($empty)
|
||||
.interact_text()?
|
||||
}};
|
||||
|
||||
($theme:expr, $prompt:expr, $empty:expr, $default:expr) => {{
|
||||
let mut theme_input = Input::with_theme($theme);
|
||||
theme_input.with_prompt($prompt).allow_empty($empty);
|
||||
if $default.len() != 0 {
|
||||
theme_input.default($default);
|
||||
}
|
||||
theme_input.interact_text()?
|
||||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! select {
|
||||
($theme:expr, $prompt:expr, $default:expr, $items:expr) => {{
|
||||
Select::with_theme($theme)
|
||||
.with_prompt($prompt)
|
||||
.default($default)
|
||||
.items($items)
|
||||
.interact()?
|
||||
}};
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
use anyhow::Result;
|
||||
use reqwest::{blocking::Client, header::USER_AGENT};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct LicenseDetails {
|
||||
#[serde(flatten)]
|
||||
base_license: License,
|
||||
|
||||
pub body: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct License {
|
||||
pub spdx_id: String,
|
||||
}
|
||||
|
||||
pub fn get_license_spdx() -> Result<Vec<String>> {
|
||||
let licenses = Client::new()
|
||||
.get(&format!("https://api.github.com/licenses",))
|
||||
.header(USER_AGENT, format!("pynit-{}", env!("CARGO_PKG_VERSION")))
|
||||
.send()?
|
||||
.json::<Vec<License>>()?;
|
||||
|
||||
Ok(licenses
|
||||
.iter()
|
||||
.map(|license| license.spdx_id.clone())
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub fn get_license(spdx: String) -> Result<LicenseDetails> {
|
||||
Ok(Client::new()
|
||||
.get(&format!("https://api.github.com/licenses/{spdx}"))
|
||||
.header(USER_AGENT, format!("pynit-{}", env!("CARGO_PKG_VERSION")))
|
||||
.send()?
|
||||
.json::<LicenseDetails>()?)
|
||||
}
|
10
src/main.rs
10
src/main.rs
|
@ -7,8 +7,11 @@ use std::{
|
|||
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use license::get_license;
|
||||
use pyproject::Pyproject;
|
||||
|
||||
mod components;
|
||||
mod license;
|
||||
mod pyproject;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, clap::ValueEnum)]
|
||||
|
@ -81,8 +84,13 @@ fn initialize_folder(
|
|||
let mut pypro = Pyproject::new(folder.clone(), complete);
|
||||
|
||||
pypro.ask_inputs()?;
|
||||
let project_name = pypro.get_project_name();
|
||||
|
||||
let project_name = pypro.get_project_name();
|
||||
|
||||
fs::write(
|
||||
folder.join("LICENSE"),
|
||||
get_license(pypro.get_license_spdx())?.body,
|
||||
)?;
|
||||
pypro.create_file()?;
|
||||
|
||||
if let Some(layout) = layout {
|
||||
|
|
116
src/pyproject.rs
116
src/pyproject.rs
|
@ -1,10 +1,12 @@
|
|||
use std::{fs, path::PathBuf};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use dialoguer::{theme::ColorfulTheme, Input};
|
||||
use dialoguer::{theme::ColorfulTheme, Input, Select};
|
||||
use regex::Regex;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{input, license::get_license_spdx, select};
|
||||
|
||||
const PYPROJECT: &str = "pyproject.toml";
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
|
@ -34,93 +36,70 @@ impl Pyproject {
|
|||
pub fn ask_inputs(&mut self) -> Result<()> {
|
||||
let theme = ColorfulTheme::default();
|
||||
|
||||
self.build_system.requires = Input::<String>::with_theme(&theme)
|
||||
.with_prompt("build dependencies (comma separated)")
|
||||
.default("setuptools,wheel".to_string())
|
||||
.interact_text()?
|
||||
self.build_system.requires = input!(&theme, "build dependencies (comma separated)", false)
|
||||
.split(',')
|
||||
.filter(|v| !v.is_empty())
|
||||
.map(|v| v.to_string())
|
||||
.collect();
|
||||
self.build_system.build_backend = Input::with_theme(&theme)
|
||||
.with_prompt("build back-end")
|
||||
.default("setuptools.build_meta".to_string())
|
||||
.interact_text()?;
|
||||
self.build_system.build_backend = input!(
|
||||
&theme,
|
||||
"build back-end",
|
||||
false,
|
||||
"setuptools.build_meta".to_string()
|
||||
);
|
||||
|
||||
// ? might want to switch to OsString instead, if the Serialize macro supports it
|
||||
let folder = match self
|
||||
.folder
|
||||
.file_name()
|
||||
.ok_or(anyhow!("project can't terminate by \"..\""))?
|
||||
.to_str()
|
||||
{
|
||||
Some(v) => Some(v.to_string()),
|
||||
None => None,
|
||||
};
|
||||
let mut input: Input<String> = Input::with_theme(&theme);
|
||||
if let Some(folder) = folder {
|
||||
self.project.name = input
|
||||
.with_prompt("project name")
|
||||
.default(folder)
|
||||
.interact_text()?;
|
||||
} else {
|
||||
self.project.name = input.with_prompt("project name").interact_text()?;
|
||||
}
|
||||
|
||||
self.project.version = Input::with_theme(&theme)
|
||||
.with_prompt("version")
|
||||
.default("0.1.0".to_string())
|
||||
.interact_text()?;
|
||||
self.project.name = input!(
|
||||
&theme,
|
||||
"project name",
|
||||
false,
|
||||
match self
|
||||
.folder
|
||||
.file_name()
|
||||
.ok_or(anyhow!("project can't terminate by \"..\""))?
|
||||
.to_str()
|
||||
{
|
||||
Some(v) => v.to_string(),
|
||||
None => String::new(),
|
||||
}
|
||||
);
|
||||
self.project.version = input!(&theme, "version", false, "0.1.0".to_string());
|
||||
|
||||
if self.complete {
|
||||
self.project.description = Input::with_theme(&theme)
|
||||
.with_prompt("description")
|
||||
.allow_empty(true)
|
||||
.interact_text()?;
|
||||
self.project.readme = Input::with_theme(&theme)
|
||||
.with_prompt("readme")
|
||||
.allow_empty(true)
|
||||
.interact_text()?;
|
||||
self.project.requires_python = Input::with_theme(&theme)
|
||||
.with_prompt("minimum python version")
|
||||
.allow_empty(true)
|
||||
.interact_text()?;
|
||||
self.project.license = Input::with_theme(&theme)
|
||||
.with_prompt("license")
|
||||
.allow_empty(true)
|
||||
.interact_text()?;
|
||||
self.project.authors = Input::<String>::with_theme(&theme)
|
||||
.with_prompt(
|
||||
self.project.description = input!(&theme, "description", true);
|
||||
self.project.readme = input!(&theme, "readme", true);
|
||||
self.project.requires_python = input!(&theme, "minimum python version", true);
|
||||
let license_spdx = get_license_spdx()?;
|
||||
let license_index = select!(
|
||||
&theme,
|
||||
"license",
|
||||
license_spdx
|
||||
.binary_search(&"MIT".into())
|
||||
.or(Err(anyhow!("MIT license not found")))?,
|
||||
&license_spdx[..]
|
||||
);
|
||||
|
||||
self.project.license = license_spdx[license_index].clone();
|
||||
self.project.authors = input!(
|
||||
&theme,
|
||||
r#"authors (e.g: "Antoine Langlois";"name="Antoine L",email="email@domain.net"")"#,
|
||||
true
|
||||
)
|
||||
.allow_empty(true)
|
||||
.interact_text()?
|
||||
.split(';')
|
||||
.filter(|v| !v.is_empty())
|
||||
.map(|v| self.parse_contributor(v))
|
||||
.collect();
|
||||
self.project.maintainers = Input::<String>::with_theme(&theme)
|
||||
.with_prompt(
|
||||
r#"maintainers (e.g: "Antoine Langlois";"name="Antoine L",email="email@domain.net"")"#,
|
||||
)
|
||||
.allow_empty(true)
|
||||
.interact_text()?
|
||||
self.project.maintainers = input!(&theme, r#"maintainers (e.g: "Antoine Langlois";"name="Antoine L",email="email@domain.net"")"#, true)
|
||||
.split(';')
|
||||
.filter(|v| !v.is_empty())
|
||||
.map(|v| self.parse_contributor(v))
|
||||
.collect();
|
||||
self.project.keywords = Input::<String>::with_theme(&theme)
|
||||
.with_prompt("keywords (e.g: KEYW1;KEYW2)")
|
||||
.allow_empty(true)
|
||||
.interact_text()?
|
||||
self.project.keywords = input!(&theme, "keywords (e.g: KEYW1;KEYW2)", true)
|
||||
.split(';')
|
||||
.filter(|v| !v.is_empty())
|
||||
.map(|v| v.to_string())
|
||||
.collect();
|
||||
self.project.classifiers = Input::<String>::with_theme(&theme)
|
||||
.with_prompt("classifiers (e.g: CLASS1;CLASS2)")
|
||||
.allow_empty(true)
|
||||
.interact_text()?
|
||||
self.project.classifiers = input!(&theme, "classifiers (e.g: CLASS1;CLASS2)", true)
|
||||
.split(';')
|
||||
.filter(|v| !v.is_empty())
|
||||
.map(|v| v.to_string())
|
||||
|
@ -157,6 +136,11 @@ impl Pyproject {
|
|||
// ? clone or maybe something else ?
|
||||
self.project.name.clone()
|
||||
}
|
||||
|
||||
pub fn get_license_spdx(&self) -> String {
|
||||
self.project.license.clone()
|
||||
}
|
||||
|
||||
/// Consume self and write everything to a `self.folder/pyproject.toml`
|
||||
pub fn create_file(self) -> Result<()> {
|
||||
fs::write(self.folder.join(PYPROJECT), toml::to_vec(&self)?)?;
|
||||
|
|
Loading…
Reference in New Issue