yuan-shen 0.0.1

A modern source code and asset version management system
#![feature(fs_try_exists)]

pub use crate::{
    cmd_checkout::YuanShenCheckout, cmd_commit::YuanShenCommit, cmd_diff::YuanShenDifference, cmd_init::YuanShenInitialize,
};
use clap::{ArgMatches, Args, FromArgMatches, Parser, Subcommand};
use clap_builder::{
    builder::{_AutoValueParser, via_prelude::_ValueParserViaParse},
    Command,
};
use std::{env::current_dir, fmt::Debug, io::stdout};
use ys_core::{
    initialize::{DotYuanShen, InitializeConfig, InsertJson},
    Ignores, ObjectID, SnapShot, SnapShotDirectory, YsError,
};

mod cmd_checkout;
mod cmd_commit;
mod cmd_diff;
mod cmd_init;

#[derive(Parser, Debug)]
struct YuanShen {
    #[clap(subcommand)]
    cmd: YsCommand,
}

#[derive(Debug)]
enum YsCommand {
    /// 创建一个新的源神世界
    Initialize(YuanShenInitialize),
    /// 观测目标世界线与当前世界的差异
    Difference(YuanShenDifference),

    Changes,

    Commit(YuanShenCommit),
    /// 将观测结果合并到当前世界线
    Squash(YuanShenSquash),
    /// 设定世界线收束节点
    Merge(YuanShenCommit),
    /// 干涉目标世界线
    Rebase(YuanShenRebase),
    /// 回溯到任意固化节点
    Reverse(YuanShenCommit),
    /// 从某一条世界线开始开启一个新世界
    Orphan(YuanShenOrphan),
    /// 切换到指定名称的世界线
    Checkout(YuanShenCheckout),
    Branch,
    Stash(YuanShenCommit),
    /// 对象有点太城市化了
    GarbageCollect,

    External(Vec<String>),
}
#[derive(Debug, Args)]
pub struct YuanShenSquash {}
#[derive(Debug, Args)]
pub struct YuanShenOrphan {}
#[derive(Debug, Args)]
pub struct YuanShenRebase {}

#[automatically_derived]
impl FromArgMatches for YsCommand {
    fn from_arg_matches(args: &ArgMatches) -> Result<Self, clap::Error> {
        Self::from_arg_matches_mut(&mut args.clone())
    }
    fn from_arg_matches_mut(args: &mut ArgMatches) -> Result<Self, clap::Error> {
        match args.remove_subcommand() {
            Some((cmd, ref mut sub_arg)) => {
                let ys_cmd = match cmd.as_str() {
                    "initialize" | "启动!" | "启动" => Self::Initialize(FromArgMatches::from_arg_matches_mut(sub_arg)?),
                    "difference" | "观测" => Self::Difference(FromArgMatches::from_arg_matches_mut(sub_arg)?),
                    "orphan" | "退相干" => Self::Orphan(FromArgMatches::from_arg_matches_mut(sub_arg)?),
                    "squash" | "塌缩" => Self::Squash(FromArgMatches::from_arg_matches_mut(sub_arg)?),
                    "merge" | "收束" => Self::Merge(FromArgMatches::from_arg_matches_mut(sub_arg)?),
                    "rebase" | "干涉" => Self::Rebase(FromArgMatches::from_arg_matches_mut(sub_arg)?),
                    "reverse" | "回溯" => Self::Reverse(FromArgMatches::from_arg_matches_mut(sub_arg)?),
                    "checkout" | "跃迁" => Self::Checkout(FromArgMatches::from_arg_matches_mut(sub_arg)?),
                    "branch" => Self::Branch,
                    "stash" => Self::Stash(FromArgMatches::from_arg_matches_mut(sub_arg)?),
                    "commit" => Self::Commit(FromArgMatches::from_arg_matches_mut(sub_arg)?),
                    "changes" => Self::Changes,
                    "garbage-collect" => Self::GarbageCollect,
                    _ => Self::External(
                        std::iter::once(String::from(cmd))
                            .chain(sub_arg.remove_many::<String>("").unwrap().map(String::from))
                            .collect::<Vec<_>>(),
                    ),
                };
                return Ok(ys_cmd);
            }
            None => Err(clap::Error::raw(
                clap::error::ErrorKind::MissingSubcommand,
                "A subcommand is required but one was not provided.",
            )),
        }
    }
    fn update_from_arg_matches(&mut self, args: &ArgMatches) -> Result<(), clap::Error> {
        self.update_from_arg_matches_mut(&mut args.clone())
    }
    fn update_from_arg_matches_mut<'b>(&mut self, args: &mut ArgMatches) -> Result<(), clap::Error> {
        match args.subcommand_name() {
            Some(clap) => match self {
                Self::Initialize(ref mut __clap_arg) if "initialize" == clap => {
                    let (_, mut __clap_arg_sub_matches) = args.remove_subcommand().unwrap();
                    let __clap_arg_matches = &mut __clap_arg_sub_matches;
                    FromArgMatches::update_from_arg_matches_mut(__clap_arg, __clap_arg_matches)?
                }
                Self::Difference(ref mut __clap_arg) if "difference" == clap => {
                    let (_, mut __clap_arg_sub_matches) = args.remove_subcommand().unwrap();
                    let __clap_arg_matches = &mut __clap_arg_sub_matches;
                    FromArgMatches::update_from_arg_matches_mut(__clap_arg, __clap_arg_matches)?
                }
                Self::Changes if "changes" == clap => {
                    let (_, mut __clap_arg_sub_matches) = args.remove_subcommand().unwrap();
                    let __clap_arg_matches = &mut __clap_arg_sub_matches;
                    {}
                }
                Self::Commit(ref mut __clap_arg) if "commit" == clap => {
                    let (_, mut __clap_arg_sub_matches) = args.remove_subcommand().unwrap();
                    let __clap_arg_matches = &mut __clap_arg_sub_matches;
                    FromArgMatches::update_from_arg_matches_mut(__clap_arg, __clap_arg_matches)?
                }
                Self::Squash(ref mut __clap_arg) if "squash" == clap => {
                    let (_, mut __clap_arg_sub_matches) = args.remove_subcommand().unwrap();
                    let __clap_arg_matches = &mut __clap_arg_sub_matches;
                    FromArgMatches::update_from_arg_matches_mut(__clap_arg, __clap_arg_matches)?
                }
                Self::Merge(ref mut __clap_arg) if "merge" == clap => {
                    let (_, mut __clap_arg_sub_matches) = args.remove_subcommand().unwrap();
                    let __clap_arg_matches = &mut __clap_arg_sub_matches;
                    FromArgMatches::update_from_arg_matches_mut(__clap_arg, __clap_arg_matches)?
                }
                Self::Rebase(ref mut __clap_arg) if "rebase" == clap => {
                    let (_, mut __clap_arg_sub_matches) = args.remove_subcommand().unwrap();
                    let __clap_arg_matches = &mut __clap_arg_sub_matches;
                    FromArgMatches::update_from_arg_matches_mut(__clap_arg, __clap_arg_matches)?
                }
                Self::Reverse(ref mut __clap_arg) if "reverse" == clap => {
                    let (_, mut __clap_arg_sub_matches) = args.remove_subcommand().unwrap();
                    let __clap_arg_matches = &mut __clap_arg_sub_matches;
                    FromArgMatches::update_from_arg_matches_mut(__clap_arg, __clap_arg_matches)?
                }
                Self::Orphan(ref mut __clap_arg) if "orphan" == clap => {
                    let (_, mut __clap_arg_sub_matches) = args.remove_subcommand().unwrap();
                    let __clap_arg_matches = &mut __clap_arg_sub_matches;
                    FromArgMatches::update_from_arg_matches_mut(__clap_arg, __clap_arg_matches)?
                }
                Self::Checkout(ref mut __clap_arg) if "checkout" == clap => {
                    let (_, mut __clap_arg_sub_matches) = args.remove_subcommand().unwrap();
                    let __clap_arg_matches = &mut __clap_arg_sub_matches;
                    FromArgMatches::update_from_arg_matches_mut(__clap_arg, __clap_arg_matches)?
                }
                Self::Branch if "branch" == clap => {
                    let (_, mut __clap_arg_sub_matches) = args.remove_subcommand().unwrap();
                    let __clap_arg_matches = &mut __clap_arg_sub_matches;
                    {}
                }
                Self::Stash(ref mut __clap_arg) if "stash" == clap => {
                    let (_, mut __clap_arg_sub_matches) = args.remove_subcommand().unwrap();
                    let __clap_arg_matches = &mut __clap_arg_sub_matches;
                    FromArgMatches::update_from_arg_matches_mut(__clap_arg, __clap_arg_matches)?
                }
                Self::GarbageCollect if "garbage-collect" == clap => {
                    let (_, mut __clap_arg_sub_matches) = args.remove_subcommand().unwrap();
                    let __clap_arg_matches = &mut __clap_arg_sub_matches;
                    {}
                }
                s => {
                    *s = <Self as FromArgMatches>::from_arg_matches_mut(args)?;
                }
            },
            None => {}
        }
        Ok(())
    }
}

impl Subcommand for YsCommand {
    fn augment_subcommands<'b>(app: Command) -> Command {
        app.subcommand({
            YuanShenInitialize::augment_args(Command::new("启动!"))
                .about("创建一个新的源神世界")
                .long_about(None)
                .alias("initialize")
                .alias("init")
                .display_name("启动!")
        })
        .subcommand({
            YuanShenDifference::augment_args(Command::new("观测"))
                .about("观测目标世界线与当前世界的差异")
                .long_about(None)
                .alias("difference")
        })
        .subcommand(Command::new("异变").alias("changes"))
        .subcommand(YuanShenCommit::augment_args(Command::new("衍化")).alias("commit"))
        .subcommand({
            YuanShenCommit::augment_args(Command::new("塌缩"))
                .about("将观测结果合并到当前世界线")
                .long_about(None)
                .alias("squash")
        })
        .subcommand({
            YuanShenCommit::augment_args(Command::new("收束")).about("设定世界线收束节点").long_about(None).alias("merge")
        })
        .subcommand({
            YuanShenCommit::augment_args(Command::new("干涉")).about("干涉目标世界线").long_about(None).alias("rebase")
        })
        .subcommand({
            YuanShenCommit::augment_args(Command::new("回溯")).about("回溯到任意固化节点").long_about(None).alias("reverse")
        })
        .subcommand({
            YuanShenOrphan::augment_args(Command::new("退相干"))
                .about("从某一条世界线开始开启一个新世界")
                .long_about(None)
                .alias("orphan")
        })
        .subcommand({
            YuanShenCheckout::augment_args(Command::new("跃迁"))
                .about("切换到指定名称的世界线")
                .long_about(None)
                .alias("checkout")
        })
        .subcommand(Command::new("branch"))
        .subcommand(YuanShenCommit::augment_args(Command::new("stash")))
        .subcommand({
            Command::new("逆城市化").about("这些对象有点太城市化了").long_about(None).alias("gc").alias("garbage-collect")
        })
        .external_subcommand_value_parser({ _AutoValueParser::<String>::new().value_parser() })
    }

    fn augment_subcommands_for_update(cmd: Command) -> Command {
        Self::augment_subcommands(cmd)
    }

    fn has_subcommand(_: &str) -> bool {
        true
    }
}

#[tokio::main]
pub async fn main() -> Result<(), YsError> {
    let args = YuanShen::parse();
    use YsCommand::*;
    match args.cmd {
        Initialize(init) => init.initialize().await?,
        Difference(diff) => diff.difference().await?,
        Branch => {
            let dot_rev = DotYuanShen::open(current_dir().unwrap().join(".ys")).unwrap();
            let branch = dot_rev.get_branch().unwrap();
            println!("{}", branch);
        }
        Checkout(c) => c.checkout().await?,
        Changes => {
            let dir = current_dir().unwrap();
            let rev_dir = dir.join(".ys");
            let dot_rev = DotYuanShen::open(rev_dir).unwrap();
            let mut store = dot_rev.store().unwrap();
            let branch: String = dot_rev.get_branch().unwrap();
            let old_tip: ObjectID = dot_rev.get_branch_snapshot_id(&branch).unwrap();
            let ignores: Ignores = dot_rev.ignores().unwrap();
            let directory = SnapShotDirectory::new(dir.as_path(), &ignores, &mut store).unwrap();
            let snapshot: SnapShot = store.read_json(old_tip).await.unwrap();
            let old_directory: SnapShotDirectory = store.read_json(snapshot.directory).await.unwrap();
            serde_json::to_writer_pretty(stdout(), &old_directory.difference(&directory)).unwrap();
        }
        Commit(sub) => sub.commit().await.unwrap(),
        Squash(_) => {}
        Merge(_) => {}
        Rebase(_) => {}
        Reverse(_) => {}
        Orphan(_) => {}
        Stash(_) => {}
        External(_) => {}
        GarbageCollect => {}
    }
    Ok(())
}