1 // SemiTwist D Tools
2 // STManage: STBuild
3 // Written in the D programming language.
4 
5 module semitwist.apps.stmanage.stbuild.cmdArgs;
6 
7 import getopt = std.getopt;
8 import semitwist.cmd.all;
9 
10 import semitwist.apps.stmanage.stbuild.conf;
11 
12 enum appName = "STBuild";
13 enum appVerStr = "0.5.2";
14 enum Ver appVer = appVerStr.toVer();
15 
16 private enum confFileWin     = "stbuild-win.conf";
17 private enum confFileLinux   = "stbuild-linux.conf";
18 private enum confFileOSX     = "stbuild-osx.conf";
19 private enum confFileBSD     = "stbuild-bsd.conf";
20 private enum confFilePosix   = "stbuild-posix.conf";
21 private enum confFileDefault = "stbuild.conf";
22 
23 struct Options
24 {
25 	bool     help;
26 	bool     cleanOnly;
27 	string   _confFile;
28 	string   buildToolStr = "rdmd";
29 	bool     quiet;
30 	bool     showCmd;
31 	string[] extraArgList;
32 	string[] targetMode;
33 
34 	// Indirectly determined by cmd line params
35 	string target;
36 	string mode = defaultMode;
37 	Conf conf;
38 	BuildTool buildTool;
39 	string extraArgs;
40 
41 	string infoHeader;
42 	string helpScreen;
43 
44 	enum seeHelpMsg = "Run with --help to see usage.";
45 	enum defaultMode = Conf.modeRelease;
46 	
47 	@property string confFile()
48 	{
49 		void setDefaultConfFile(string file)
50 		{
51 			if(_confFile == "" && exists(file))
52 				_confFile = file;
53 		}
54 		version(Windows)      setDefaultConfFile(confFileWin);
55 		version(linux)        setDefaultConfFile(confFileLinux);
56 		version(FreeBSD)      setDefaultConfFile(confFileBSD);
57 		version(OpenBSD)      setDefaultConfFile(confFileBSD);
58 		version(NetBSD)       setDefaultConfFile(confFileBSD);
59 		version(DragonFlyBSD) setDefaultConfFile(confFileBSD);
60 		version(OSX)          setDefaultConfFile(confFileOSX);
61 		version(Posix)        setDefaultConfFile(confFilePosix);
62 		if(_confFile == "")
63 			_confFile = confFileDefault;
64 		
65 		return _confFile;
66 	}
67 	
68 	// Returns errorlevel program should exit immediately with.
69 	// If returns -1, everything is OK and program should continue without exiting.
70 	int process(string[] args)
71 	{
72 		infoHeader = (`
73 				`~appName~` v`~appVerStr~`
74 				Copyright (c) 2009-2013 Nick Sabalausky
75 				See LICENSE.txt for license info
76 				Site: http://www.dsource.org/projects/semitwist
77 			`).normalize();
78 		
79 		helpScreen = `
80 				Usage: stbuild [options] target [mode] [options]
81 
82 				--help              Displays this help screen and exits
83 				--clean             Clean, don't build
84 				--conf <filename>   Configuration file to use (default: "stbuild-(os).conf" or else "stbuild.conf")
85 				--tool <tool>       Build tool ["rdmd", "re" or "xf"] (default: "rdmd")
86 				-q, --quiet         Quiet, ie. don't show progress messages
87 				--cmd               Show commands
88 				-x <arg>            Pass extra argument to build tool
89 			`.normalize();
90 
91 		if(args.length == 1)
92 			return showHelpScreen();
93 
94 		getopt.endOfOptions = "";
95 		try getopt.getopt(
96 			args,
97 			getopt.config.caseSensitive,
98 			"help",     &help,
99 			"clean",    &cleanOnly,
100 			"conf",     &_confFile,
101 			"tool",     &buildToolStr,
102 			"q|quiet",  &quiet,
103 			"cmd",      &showCmd,
104 			"x",        &extraArgList
105 		);
106 		catch(Exception e)
107 		{
108 			writeln(e.msg);
109 			writeln(seeHelpMsg);
110 			return 1;
111 		}
112 		
113 		targetMode = args[1..$];
114 
115 		if(help || args.contains("/?"))
116 			return showHelpScreen();
117 		
118 		try
119 			conf = new Conf(confFile);
120 		catch(STBuildConfException e)
121 		{
122 			stderr.writeln(e.msg);
123 			stderr.writeln(seeHelpMsg);
124 			return false;
125 		}
126 
127 		switch(targetMode.length)
128 		{
129 		case 1:
130 			target = targetMode[0];
131 			break;
132 		case 2:
133 			target = targetMode[0];
134 			mode   = targetMode[1];
135 			break;
136 		case 0:
137 			stderr.writeln("Must specify a target.");
138 			stderr.writeln(seeHelpMsg);
139 			return 1;
140 		default:
141 			stderr.writeln("Unexpected extra params: ", targetMode[2..$]);
142 			stderr.writeln(seeHelpMsg);
143 			return 1;
144 		}
145 		
146 		switch(buildToolStr)
147 		{
148 		case "rdmd":
149 			buildTool = BuildTool.rdmd;
150 			break;
151 		case "re", "rebuild":
152 			buildTool = BuildTool.rebuild;
153 			break;
154 		case "xf", "xfbuild":
155 			buildTool = BuildTool.xfbuild;
156 			break;
157 		default:
158 			stderr.writeln("Unknown build tool: '", buildToolStr, "'");
159 			stderr.writeln(seeHelpMsg);
160 			return 1;
161 		}
162 		
163 		extraArgs = std..string.join(extraArgList, " ");
164 		
165 		// Move to CmdLine
166 		if(find(conf.targets, target) == [])
167 		{
168 			stderr.writeln("Unknown target: '", target, "'");
169 			showTargets();
170 			stderr.writeln(seeHelpMsg);
171 			return 1;
172 		}
173 		if(find(conf.getModes(), mode) == [])
174 		{
175 			stderr.writeln("Unknown mode: '", mode, "'");
176 			showModes();
177 			stderr.writeln(seeHelpMsg);
178 			return 1;
179 		}
180 		
181 		return -1; // All ok
182 	}
183 
184 	private void showTargets()
185 	{
186 		if(conf && conf.targets.length > conf.predefTargets.length)
187 		{
188 			//TODO: Create array.moveIndex(index, newIndex)
189 			//TODO: Create array.moveElement(elem, newIndex)
190 			//TODO: Make "all" always first
191 			auto targets = conf.targets.dup;
192 			targets.sort();
193 
194 			cmd.echo("Targets Available:", targets);
195 		}
196 		else
197 			cmd.echo("No Targets Available");
198 		cmd.echo();
199 	}
200 	
201 	private void showModes()
202 	{
203 		string[] modes;
204 		if(conf)
205 			modes = conf.getModes();
206 
207 		if(modes.length > 0)
208 		{
209 			modes.sort();
210 
211 			cmd.echo("Modes:", modes);
212 			cmd.echo("Default Mode:", defaultMode);
213 		}
214 		else
215 			cmd.echo("No Modes Available");
216 		cmd.echo();
217 	}
218 
219 	private void showUsage()
220 	{
221 		showTargets();
222 		showModes();
223 		writeln(helpScreen);
224 	}
225 
226 	private void showHeader()
227 	{
228 		writeln(infoHeader);
229 		writeln();
230 	}
231 
232 	private int showHelpScreen()
233 	{
234 		if(!conf)
235 		{
236 			try
237 				conf = new Conf(confFile);
238 			catch(STBuildConfException e)
239 			{
240 				stderr.writeln(e.msg);
241 				stderr.writeln(seeHelpMsg);
242 				return 1;
243 			}
244 		}
245 
246 		showHeader();
247 		showUsage();
248 		return 0;
249 	}
250 }