public static ModuleSet FromEnumerable(IEnumerable <Module> source) { var result = new ModuleSet(); foreach (var module in source) { result.Add(module); } return(result); }
public int RegisterCommandClass( CommandEvaluationContext context, Type type, bool registerAsModule ) { if (type.GetInterface(typeof(ICommandsDeclaringType).FullName) == null) { throw new Exception($"the type '{type.FullName}' must implements interface '{typeof(ICommandsDeclaringType).FullName}' to be registered as a command class"); } var dtNamespaceAttr = type.GetCustomAttribute <CommandsNamespaceAttribute>(); var dtNamespace = (dtNamespaceAttr == null) ? "" : CheckAndNormalizeCommandNamespace(dtNamespaceAttr.Segments); var comsCount = 0; object instance = Activator.CreateInstance(type, new object[] { }); var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); if (registerAsModule && _modules.ContainsKey(type.FullName)) { context.Errorln($"a module with same name than the commands declaring type '{type.FullName}' is already registered"); return(0); } foreach (var method in methods) { var cmd = method.GetCustomAttribute <CommandAttribute>(); if (cmd != null) { if (!method.ReturnType.HasInterface(typeof(ICommandResult))) { context.Errorln($"class={type.FullName} method={method.Name} wrong return type. should be of type '{typeof(ICommandResult).FullName}', but is of type: {method.ReturnType.FullName}"); } else { // ⏺ build the command specification from the method meta-data var cmdNamespaceAttr = method.GetCustomAttribute <CommandNamespaceAttribute>(); var cmdNamespace = cmdNamespaceAttr == null ? dtNamespace : CheckAndNormalizeCommandNamespace(cmdNamespaceAttr.Segments); var cmdAliasesAttrLst = method.GetCustomAttributes <CommandAliasAttribute>(); var cmdAliases = cmdAliasesAttrLst?.Select(x => (x.AliasName, x.AliasText)).ToList(); if (cmdAliases.Count == 0) { cmdAliases = null; // convention } #region init from method parameters attributes var paramspecs = new List <CommandParameterSpecification>(); bool syntaxError = false; var pindex = 0; foreach (var parameter in method.GetParameters()) { if (pindex == 0) { // manadatory: param 0 is CommandEvaluationContext if (parameter.ParameterType != typeof(CommandEvaluationContext)) { context.Errorln($"class={type.FullName} method={method.Name} parameter 0 ('{parameter.Name}') should be of type '{typeof(CommandEvaluationContext).FullName}', but is of type: {parameter.ParameterType.FullName}"); syntaxError = true; break; } } else { CommandParameterSpecification pspec = null; object defval = null; if (!parameter.HasDefaultValue && parameter.ParameterType.IsValueType) { defval = Activator.CreateInstance(parameter.ParameterType); } // param var paramAttr = parameter.GetCustomAttribute <ParameterAttribute>(); if (paramAttr != null) { // TODO: validate command specification (eg. indexs validity) pspec = new CommandParameterSpecification( parameter.Name, paramAttr.Description, paramAttr.IsOptional, paramAttr.Index, null, null, true, parameter.HasDefaultValue, paramAttr.HasDefaultValue ? paramAttr.DefaultValue : ((parameter.HasDefaultValue) ? parameter.DefaultValue : defval), parameter); } // option var optAttr = parameter.GetCustomAttribute <OptionAttribute>(); if (optAttr != null) { var reqParamAttr = parameter.GetCustomAttribute <OptionRequireParameterAttribute>(); try { pspec = new CommandParameterSpecification( parameter.Name, optAttr.Description, optAttr.IsOptional, -1, optAttr.OptionName /*?? parameter.Name*/, optAttr.OptionLongName, optAttr.HasValue, parameter.HasDefaultValue, optAttr.HasDefaultValue ? optAttr.DefaultValue : ((parameter.HasDefaultValue) ? parameter.DefaultValue : defval), parameter, reqParamAttr?.RequiredParameterName); } catch (Exception ex) { context.Errorln(ex.Message); } } if (pspec == null) { syntaxError = true; context.Errorln($"invalid parameter: class={type.FullName} method={method.Name} name={parameter.Name}"); } else { paramspecs.Add(pspec); } } pindex++; } #endregion if (!syntaxError) { var cmdNameAttr = method.GetCustomAttribute <CommandNameAttribute>(); var cmdName = CheckAndNormalizeCommandName( (cmdNameAttr != null && cmdNameAttr.Name != null) ? cmdNameAttr.Name : (cmd.Name ?? method.Name)); bool registered = true; CommandSpecification cmdspec = null; try { cmdspec = new CommandSpecification( cmdNamespace, cmdName, cmd.Description, cmd.LongDescription, cmd.Documentation, method, instance, cmdAliases, paramspecs); } catch (Exception ex) { context.Errorln($"error in command '{cmdName}' specification: {ex.Message}"); } if (cmdspec != null) { if (_commands.TryGetValue(cmdspec.Name, out var cmdlst)) { if (cmdlst.Select(x => x.MethodInfo.DeclaringType == type).Any()) { context.Errorln($"command already registered: '{cmdspec.Name}' in type '{cmdspec.DeclaringTypeFullName}'"); registered = false; } else { cmdlst.Add(cmdspec); } } else { _commands.Add(cmdspec.Name, new List <CommandSpecification> { cmdspec }); } if (registered) { _syntaxAnalyzer.Add(cmdspec); comsCount++; // register command Aliases if (cmdspec.Aliases != null) { foreach (var alias in cmdspec.Aliases) { context.CommandLineProcessor.CommandsAlias.AddOrReplaceAlias( context, alias.name, alias.text ); } } } } } } } } if (registerAsModule) { if (comsCount == 0) { context.Errorln($"no commands found in type '{type.FullName}'"); } else { var descAttr = type.GetCustomAttribute <CommandsAttribute>(); var description = descAttr != null ? descAttr.Description : ""; _modules.Add( type.FullName, // key not from assembly but from type new ModuleSpecification( type.FullName, ModuleUtil.DeclaringTypeShortName(type), description, type.Assembly, new ModuleInfo( 1, comsCount ), type )); } } return(comsCount); }
public ModuleSpecification RegisterModule( CommandEvaluationContext context, Assembly assembly) { ModuleSpecification moduleSpecification; var moduleAttr = assembly.GetCustomAttribute <ShellModuleAttribute>(); if (moduleAttr == null) { context.Errorln($"assembly is not a shell module: '{assembly.FullName}'"); return(ModuleSpecification.ModuleSpecificationNotDefined); } var id = assembly.GetCustomAttribute <AssemblyTitleAttribute>()?.Title ?? throw new Exception($"module id missing in assembly '{assembly.ManifestModule.Name}' ('AssemblyTitle' attribute missing)"); var ver = assembly.GetCustomAttribute <AssemblyInformationalVersionAttribute>()?.InformationalVersion ?? throw new Exception($"module version missing in assembly '{assembly.ManifestModule.Name}' ('AssemblyInformationalVersion' attribute missing)"); var modKey = GetModuleLowerId(id, ver); if (_modules.ContainsKey(modKey)) { context.Errorln($"module already registered: {modKey} (path={assembly.FullName})"); return(ModuleSpecification.ModuleSpecificationNotDefined); } var typesCount = 0; var comTotCount = 0; var hooksCount = 0; foreach (var type in assembly.GetTypes()) { // register hooks var hookAttr = type.GetCustomAttribute <HooksAttribute>(); if (hookAttr != null) { // module,class owns hooks foreach (var mi in type.GetMethods(BindingFlags.Public | BindingFlags.Instance)) { var hook = mi.GetCustomAttribute <HookAttribute>(); if (hook != null) { ModuleHookManager.RegisterHook(context, hook.HookName, mi); hooksCount++; } } } // register commands var comsAttr = type.GetCustomAttribute <CommandsAttribute>(); var comCount = 0; if (comsAttr != null && type.GetInterface(typeof(ICommandsDeclaringType).FullName) != null) { comCount = ModuleCommandManager.RegisterCommandClass(context, type, false); } if (comCount > 0) { typesCount++; } comTotCount += comCount; } // register module var descAttr = assembly.GetCustomAttribute <AssemblyDescriptionAttribute>(); var description = (descAttr != null) ? descAttr.Description : ""; _modules.Add( modKey, moduleSpecification = new ModuleSpecification( modKey, Path.GetFileNameWithoutExtension(assembly.Location), description, assembly, new ModuleInfo( typesCount, comTotCount, hooksCount ) )); // run module hook init ModuleHookManager.InvokeHooks( context, Hooks.ModuleInit, (o) => { moduleSpecification.IsInitialized = true; } ); return(moduleSpecification); }
public ModuleSpecification RegisterModule( CommandEvaluationContext context, Assembly assembly) { ModuleSpecification moduleSpecification; var moduleAttr = assembly.GetCustomAttribute <ShellModuleAttribute>(); if (moduleAttr == null) { context.Errorln($"assembly is not a shell module: '{assembly.FullName}'"); return(ModuleSpecification.ModuleSpecificationNotDefined); } // id is the name of the assembly (/!\ should not fit nuget packet id) var modKey = _moduleKey(assembly, out var id, out var ver); var assKey = _assemblyKey(assembly); if (_loadedModules.Contains(assKey)) { throw new Exception($"assembly already loaded: '{assKey}'"); } if (_modules.ContainsKey(modKey)) { context.Errorln($"module already registered: {modKey} (path={assembly.FullName})"); return(ModuleSpecification.ModuleSpecificationNotDefined); } var typesCount = 0; var comTotCount = 0; var hooksCount = 0; foreach (var type in assembly.GetTypes()) { // register hooks var hookAttr = type.GetCustomAttribute <HooksAttribute>(); if (hookAttr != null) { // module,class owns hooks foreach (var mi in type.GetMethods(BindingFlags.Public | BindingFlags.Instance)) { var hook = mi.GetCustomAttribute <HookAttribute>(); if (hook != null) { ModuleHookManager.RegisterHook(context, hook.HookName, mi); hooksCount++; } } } // register commands var comsAttr = type.GetCustomAttribute <CommandsAttribute>(); var comCount = 0; if (comsAttr != null && type.GetInterface(typeof(ICommandsDeclaringType).FullName) != null) { comCount = ModuleCommandManager.RegisterCommandClass(context, type, false); } if (comCount > 0) { typesCount++; } comTotCount += comCount; } // register module var descAttr = assembly.GetCustomAttribute <AssemblyDescriptionAttribute>(); var description = (descAttr != null) ? descAttr.Description : ""; _modules.Add( modKey, moduleSpecification = new ModuleSpecification( modKey, Path.GetFileNameWithoutExtension(assembly.Location), description, assembly, new ModuleInfo( typesCount, comTotCount, hooksCount ) )); _loadedModules.Add(_assemblyKey(assembly)); _loadedAssemblies.Add(assembly.Location.ToLower()); // run module hook init ModuleHookManager.InvokeHooks( context, Hooks.ModuleInit, HookTriggerMode.FirstTimeOnly, (o) => { moduleSpecification.IsInitialized = true; } ); return(moduleSpecification); }