1 /******************************************************************************* 2 3 Application class that provides the standard features needed by command 4 line tools: 5 * Command line parsing 6 * Version support 7 8 Usage example: 9 See CliApp class' documented unittest 10 11 Copyright: 12 Copyright (c) 2009-2016 dunnhumby Germany GmbH. 13 All rights reserved. 14 15 License: 16 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details. 17 Alternatively, this file may be distributed under the terms of the Tango 18 3-Clause BSD License (see LICENSE_BSD.txt for details). 19 20 *******************************************************************************/ 21 22 module ocean.util.app.CliApp; 23 24 25 import ocean.util.app.Application : Application; 26 import ocean.util.app.ext.model.IArgumentsExtExtension; 27 import ocean.task.IScheduler; 28 29 import ocean.meta.types.Qualifiers; 30 31 /******************************************************************************* 32 33 CliApp class 34 35 *******************************************************************************/ 36 37 abstract class CliApp : Application, IArgumentsExtExtension 38 { 39 static import ocean.text.Arguments; 40 public alias ocean.text.Arguments.Arguments Arguments; 41 42 import ocean.util.app.ext.ArgumentsExt; 43 import ocean.util.app.ext.VersionArgsExt; 44 import ocean.util.app.ext.TaskExt; 45 46 protected import ocean.util.app.ext.VersionInfo : VersionInfo; 47 48 /*************************************************************************** 49 50 Command line arguments used by the application. 51 52 ***************************************************************************/ 53 54 public Arguments args; 55 56 /*************************************************************************** 57 58 Command line arguments extension used by the application. 59 60 ***************************************************************************/ 61 62 public ArgumentsExt args_ext; 63 64 /*************************************************************************** 65 66 Version information. 67 68 ***************************************************************************/ 69 70 public VersionInfo ver; 71 72 /*************************************************************************** 73 74 Version information extension. 75 76 ***************************************************************************/ 77 78 public VersionArgsExt ver_ext; 79 80 /*************************************************************************** 81 82 Extension to start `run` method inside a task. 83 84 ***************************************************************************/ 85 86 public TaskExt task_ext; 87 88 /*************************************************************************** 89 90 Struct containing optional constructor arguments. There are enough of 91 these that handling them as default arguments to the ctor is cumbersome. 92 93 ***************************************************************************/ 94 95 public static struct OptionalSettings 96 { 97 /*********************************************************************** 98 99 How the program is supposed to be invoked. 100 101 ***********************************************************************/ 102 103 istring usage = null; 104 105 /*********************************************************************** 106 107 Long description of what the program does and how to use it. 108 109 ***********************************************************************/ 110 111 istring help = null; 112 113 /*********************************************************************** 114 115 By default TaskExt is disabled to prevent breaking change for 116 applications already configuring scheduler on their own. 117 118 ***********************************************************************/ 119 120 bool use_task_ext; 121 122 /*********************************************************************** 123 124 Only used if `use_task_ext` is set to `true`. Defines scheduler 125 configuration to be used by TaskExt. 126 127 ***********************************************************************/ 128 129 IScheduler.Configuration scheduler_config; 130 } 131 132 /*************************************************************************** 133 134 This constructor only sets up the internal state of the class, but does 135 not call any extension or user code. 136 137 Params: 138 name = Name of the application (to show in the help message) 139 desc = Short description of what the program does (should be 140 one line only, preferably less than 80 characters) 141 ver = application's version information 142 settings = optional settings (see OptionalSettings, above) 143 144 ***************************************************************************/ 145 146 public this ( istring name, istring desc, VersionInfo ver, 147 OptionalSettings settings = OptionalSettings.init ) 148 { 149 super(name, desc); 150 151 // Create and register arguments extension 152 this.args_ext = new ArgumentsExt(name, desc, settings.usage, 153 settings.help); 154 this.args = this.args_ext.args; 155 this.args_ext.registerExtension(this); 156 this.registerExtension(this.args_ext); 157 158 // Create and register version extension 159 this.ver_ext = new VersionArgsExt(ver); 160 this.ver = this.ver_ext.ver; 161 this.args_ext.registerExtension(this.ver_ext); 162 this.registerExtension(this.ver_ext); 163 164 if (settings.use_task_ext) 165 { 166 this.task_ext = new TaskExt(settings.scheduler_config); 167 // initialises scheduler even if config is not present: 168 this.task_ext.processConfig(null, null); 169 } 170 } 171 172 /*************************************************************************** 173 174 Run implementation that forwards to the abstract 175 run(Arguments, ConfigParser). 176 177 Params: 178 args = raw command line arguments 179 180 Returns: 181 status code to return to the OS 182 183 ***************************************************************************/ 184 185 override protected int run ( istring[] args ) 186 { 187 if (this.task_ext is null) 188 return this.run(this.args); 189 190 return this.task_ext.run(&this.mainForTaskExt); 191 } 192 193 /*************************************************************************** 194 195 Used inside `run` if TaskExt is enabled to workaround double `this` 196 issue with inline delegate literal 197 198 ***************************************************************************/ 199 200 private int mainForTaskExt ( ) 201 { 202 return this.run(this.args); 203 } 204 205 /*************************************************************************** 206 207 This method must be implemented by subclasses to do the actual 208 application work. 209 210 Params: 211 args = parsed command line arguments 212 213 Returns: 214 status code to return to the OS 215 216 ***************************************************************************/ 217 218 abstract protected int run ( Arguments args ); 219 220 /*************************************************************************** 221 222 IArgumentsExtExtension methods dummy implementation. 223 224 These methods are implemented with an "empty" implementation to ease 225 deriving from this class. 226 227 See IArgumentsExtExtension documentation for more information on how to 228 override these methods. 229 230 ***************************************************************************/ 231 232 override public void setupArgs ( IApplication app, Arguments args ) 233 { 234 // Dummy implementation of the interface 235 } 236 237 override public void preValidateArgs ( IApplication app, Arguments args ) 238 { 239 // Dummy implementation of the interface 240 } 241 242 override public cstring validateArgs ( IApplication app, Arguments args ) 243 { 244 // Dummy implementation of the interface 245 return null; 246 } 247 248 override public void processArgs ( IApplication app, Arguments args ) 249 { 250 // Dummy implementation of the interface 251 } 252 } 253 254 /// 255 unittest 256 { 257 /*************************************************************************** 258 259 Example CLI application class. 260 261 ***************************************************************************/ 262 263 class MyApp : CliApp 264 { 265 this ( ) 266 { 267 // The name of your app and a short description of what it does. 268 istring name = "my_app"; 269 istring desc = "Dummy app for unittest."; 270 271 // The version info for your app. Normally you get this by importing 272 // Version and passing the AA which contains the version info 273 // (called Version) to CliApp's constructor. 274 auto ver = VersionInfo.init; 275 276 // You may also pass an instance of OptionalSettings to CliApp's 277 // constructor, to specify non-mandatory options. In this example, 278 // we specify the help text. 279 CliApp.OptionalSettings settings; 280 settings.help = "Actually, this program does nothing. Sorry!"; 281 282 // Call the super class' ctor. 283 super(name, desc, ver, settings); 284 } 285 286 // Called after arguments and config file parsing. 287 override protected int run ( Arguments args ) 288 { 289 // Application main logic. 290 291 return 0; // return code to OS 292 } 293 } 294 295 /*************************************************************************** 296 297 Your application's main() function should look something like this. 298 (This function is not called here as we don't want to actually run the 299 application in this unittest.) 300 301 ***************************************************************************/ 302 303 int main ( istring[] cl_args ) 304 { 305 // Instantiate an instance of your app class. 306 auto my_app = new MyApp; 307 308 // Pass the raw command line arguments to its main function. 309 auto ret = my_app.main(cl_args); 310 311 // Return ret to the OS. 312 return ret; 313 } 314 } 315