1 /**
2  * Copyright: Copyright (c) 2010-2011 Jacob Carlborg. All rights reserved.
3  * Authors: Jacob Carlborg
4  * Version: Initial created: Aug 15, 2010
5  * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
6  */
7 module dvm.dvm.Application;
8 
9 import tango.core.Exception;
10 import tango.io.device.File;
11 import tango.io.Stdout;
12 import tango.net.http.HttpGet;
13 import tango.stdc.stdlib : EXIT_SUCCESS, EXIT_FAILURE;
14 import tango.text.Arguments;
15 import tango.text.convert.Format : Format;
16 
17 import dvm.dvm._;
18 import dvm.util._;
19 import mambo.core._;
20 import mambo.util._;
21 
22 static import dvm.commands._;
23 
24 version (Windows)
25 {
26     pragma(lib, "zlib.lib");
27     pragma(lib, "Advapi32.lib");
28 }
29 
30 class Application
31 {
32     private static Application instance_;
33 
34     private
35     {
36         alias Format format;
37         string[] args;
38         Options options;
39         CommandManager commandManager;
40     }
41 
42     static Application instance ()
43     {
44         if (instance_)
45             return instance_;
46 
47         return instance_ = new Application;
48     }
49 
50     private this ()
51     {
52         options = Options.instance;
53         commandManager = CommandManager.instance;
54 
55         registerCommands;
56     }
57 
58     int run (string[] args)
59     {
60         this.args = args;
61 
62         return handleExceptions in {
63             parseOptions();
64             return EXIT_SUCCESS;
65         };
66     }
67 
68     Use!(int delegate ()) handleExceptions ()
69     {
70         Use!(int delegate ()) use;
71 
72         use.args[0] = (int delegate () dg) {
73             try
74                 return dg();
75 
76             catch (DvmException e)
77             {
78                 stderr.format("An error occurred: {}", e).newline.flush;
79                 return EXIT_FAILURE;
80             }
81 
82             catch (Exception e)
83             {
84                 stderr.format("An unknown error occurred:").newline;
85                 throw e;
86             }
87         };
88 
89         return use;
90     }
91 
92     Use!(int delegate ()) debugHandleExceptions ()
93     {
94         Use!(int delegate ()) use;
95 
96         use.args[0] = (int delegate () dg) {
97             return dg();
98         };
99 
100         return use;
101     }
102 
103     private void registerCommands ()
104     {
105         commandManager.register("dvm.commands.Install.Install");
106         commandManager.register("dvm.commands.Fetch.Fetch");
107         commandManager.register("dvm.commands.Use.Use");
108         commandManager.register("dvm.commands.List.List");
109         commandManager.register("dvm.commands.Compile.Compile");
110         commandManager.register("dvm.commands.Uninstall.Uninstall");
111     }
112 
113     void handleArgs (string[] args)
114     {
115         if (args.length > 0)
116         {
117             string command;
118 
119             switch (args[0])
120             {
121                 case "install":    command = "dvm.commands.Install.Install"; break;
122                 case "fetch": command = "dvm.commands.Fetch.Fetch"; break;
123                 case "use": command = "dvm.commands.Use.Use"; break;
124                 case "list": command = "dvm.commands.List.List"; break;
125                 case "compile": command = "dvm.commands.Compile.Compile"; break;
126                 case "uninstall": command = "dvm.commands.Uninstall.Uninstall"; break;
127                 default:
128                     return unhandledCommand(args[0]);
129             }
130 
131             handleCommand(command, args[1 .. $]);
132         }
133     }
134 
135     void handleCommand (string command, string[] args)
136     {
137         commandManager[command].invoke(args);
138     }
139 
140     void unhandledCommand (string command)
141     {
142         throw new DvmException("unrecognized command " ~ `"` ~ command ~ `"` ~ "\n", __FILE__, __LINE__);
143     }
144 
145     void parseOptions ()
146     {
147         auto helpMessage = "Use the `-h' flag for help.";
148         auto opts = new OptionParser;
149         auto commands = CommandManager.instance.summary;
150         auto help = false;
151         auto version_ = false;
152 
153         opts.banner = "Usage: dvm [options] command [arg]";
154         opts.separator("Version " ~ dvm.dvm.Version.Version);
155         opts.separator("");
156         opts.separator("Commands:");
157         opts.separator(commands);
158         opts.separator("Options:");
159 
160         opts.on('d', "default", "Sets the default D compiler for new shells.", {
161             options.isDefault = true;
162         });
163 
164         opts.on('l', "latest", "Gets the latest D compiler.", {
165             options.latest = true;
166         });
167 
168         version (Posix)
169         {
170             opts.on("64bit", "Installs the 64bit version of the compiler.", {
171                 options.is64bit = true;
172             });
173 
174             opts.on("32bit", "Installs the 32bit version of the compiler.", {
175                 options.is64bit = false;
176             });
177         }
178 
179         opts.on('t', "tango", "Installs Tango as the standard library.", {
180             options.tango = true;
181         });
182 
183         opts.on('v', "verbose", "Show additional output.", {
184             options.verbose = true;
185         });
186 
187         opts.on("force", "Answer 'yes' to all prompts.", {
188             options.force = true;
189         });
190 
191         opts.on("decline", "Answer 'no' to all prompts.", {
192             options.decline = true;
193         });
194 
195         opts.on("debug", "Compile DMD in debug mode.", {
196             options.compileDebug = true;
197         });
198 
199         opts.on('V', "version", "Print the version of DVM and exit.", {
200             version_ = true;
201         });
202 
203         opts.on('h', "help", "Show this message and exit.", {
204             help = true;
205         });
206 
207         opts.on((string[] args) {
208             if (options.force && options.decline)
209                 throw new InvalidOptionException("Cannot use both --force and --decline", __FILE__, __LINE__);
210 
211             else if (!help)
212                 handleArgs(args);
213         });
214 
215         opts.parse(args[1 .. $]);
216 
217         if (version_)
218             println(dvm.dvm.Version.Version);
219 
220         else if (args.length == 1 || help)
221         {
222             println(opts);
223             println(helpMessage);
224         }
225     }
226 }