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