Skip to content
This repository was archived by the owner on Jun 3, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
207 changes: 33 additions & 174 deletions src/main/java/fi/helsinki/cs/tmc/cli/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,91 +3,66 @@
import fi.helsinki.cs.tmc.cli.command.core.AbstractCommand;
import fi.helsinki.cs.tmc.cli.command.core.CommandFactory;
import fi.helsinki.cs.tmc.cli.io.Color;
import fi.helsinki.cs.tmc.cli.io.EnvironmentUtil;
import fi.helsinki.cs.tmc.cli.io.HelpGenerator;
import fi.helsinki.cs.tmc.cli.io.Io;
import fi.helsinki.cs.tmc.cli.io.TerminalIo;
import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfo;
import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfoIo;
import fi.helsinki.cs.tmc.cli.tmcstuff.Settings;
import fi.helsinki.cs.tmc.cli.tmcstuff.SettingsIo;
import fi.helsinki.cs.tmc.cli.io.ShutdownHandler;
import fi.helsinki.cs.tmc.cli.tmcstuff.WorkDir;
import fi.helsinki.cs.tmc.cli.updater.TmcCliUpdater;

import fi.helsinki.cs.tmc.core.TmcCore;
import fi.helsinki.cs.tmc.core.domain.Course;
import fi.helsinki.cs.tmc.langs.util.TaskExecutor;
import fi.helsinki.cs.tmc.langs.util.TaskExecutorImpl;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
import java.util.Map;

/**
* The application class for the program.
* TODO: we should move all the command line related code to
* somewhere else from here.
*/
public class Application {
private static final Logger logger = LoggerFactory.getLogger(Application.class);
private static final String previousUpdateDateKey = "update-date";
private static final long defaultUpdateInterval = 60 * 60 * 1000;
private static final String usage = "tmc [args] COMMAND [command-args]";

private CommandFactory commandFactory;
private HashMap<String, String> properties;
private TmcCore tmcCore;
private Settings settings;
private WorkDir workDir;
private Io io;

private boolean inTest;
private ShutdownHandler shutdownHandler;
private final CliContext context;
private final Io io;

private Options options;
private GnuParser parser;
private final Options options;
private final GnuParser parser;
private String commandName;

public Application(Io io) {
public Application(CliContext context) {
this.parser = new GnuParser();
this.options = new Options();
this.commandFactory = new CommandFactory();

this.context = context;
this.io = context.getIo();

options.addOption("h", "help", false, "Display help information about tmc-cli");
options.addOption("v", "version", false, "Give the version of the tmc-cli");

inTest = true;
if (io == null) {
inTest = false;
io = new TerminalIo();
shutdownHandler = new ShutdownHandler(io);
Runtime.getRuntime().addShutdownHook(shutdownHandler);
//TODO implement the inTests as context.property
if (!context.inTests()) {
shutdownHandler = new ShutdownHandler(context.getIo());
shutdownHandler.enable();
}

this.io = io;
this.workDir = new WorkDir();
this.properties = SettingsIo.loadProperties();
}

public Application(Io io, WorkDir workDir) {
this(io);
this.workDir = workDir;
this(new CliContext(io, workDir));
}

private boolean runCommand(String name, String[] args) {
AbstractCommand command = commandFactory.createCommand(this, name);
AbstractCommand command = CommandFactory.createCommand(this.context, name);
if (command == null) {
io.println("Command " + name + " doesn't exist.");
return false;
Expand Down Expand Up @@ -129,7 +104,7 @@ private String[] parseArgs(String[] args) {
return null;
}
if (line.hasOption("v")) {
io.println("TMC-CLI version " + getVersion());
io.println("TMC-CLI version " + EnvironmentUtil.getVersion());
return null;
}
return subArgs.toArray(new String[subArgs.size()]);
Expand All @@ -140,7 +115,9 @@ public void printHelp(String description) {
}

public void run(String[] args) {
if (!inTest) {
context.setApp(this);

if (!context.inTests()) {
versionCheck();
}

Expand All @@ -151,138 +128,18 @@ public void run(String[] args) {

runCommand(commandName, commandArgs);

if (!inTest) {
Runtime.getRuntime().removeShutdownHook(shutdownHandler);
if (!context.inTests()) {
shutdownHandler.disable();
}
}

public void createTmcCore(Settings settings) {
TaskExecutor tmcLangs;

tmcLangs = new TaskExecutorImpl();
this.settings = settings;
this.tmcCore = new TmcCore(settings, tmcLangs);
/*XXX should we somehow check if the authentication is successful here */
Path path = getWorkDir().getCourseDirectory();
if (path == null) {
settings.setTmcProjectDirectory(Paths.get(System.getProperty("user.dir")));
return;
}
settings.setTmcProjectDirectory(path.getParent());
}

public CommandFactory getCommandFactory() {
return this.commandFactory;
}

// Method is used to help testing
public void setTmcCore(TmcCore tmcCore) {
this.tmcCore = tmcCore;
}

public TmcCore getTmcCore() {
if (this.tmcCore == null) {
SettingsIo settingsio = new SettingsIo();
Settings settings;

if (workDir.getConfigFile() != null) {
// If we're in a course directory, we load settings matching the course
// Otherwise we just load the last used settings
CourseInfo courseinfo = CourseInfoIo.load(workDir.getConfigFile());
if (courseinfo == null) {
io.println("Course configuration file "
+ workDir.getConfigFile().toString()
+ "is invalid.");
return null;
}
settings = settingsio.load(courseinfo.getUsername(),
courseinfo.getServerAddress());
} else {
settings = settingsio.load();
}

if (settings == null) {
// If no settings are present
io.println("You are not logged in. Log in using: tmc login");
return null;
}
createTmcCore(settings);
}
return this.tmcCore;
}

public void setSettings(Settings settings) {
this.settings = settings;
}

public static void main(String[] args) {
Application app = new Application(null);
Application app = new Application(new CliContext(null));
app.run(args);
}

public static String getVersion() {
String path = "/maven.prop";
InputStream stream = Application.class.getResourceAsStream(path);
if (stream == null) {
return "n/a";
}

Properties props = new Properties();
try {
props.load(stream);
stream.close();
return (String) props.get("version");
} catch (IOException e) {
logger.warn("Failed to get version", e);
return "n/a";
}
}

public WorkDir getWorkDir() {
return this.workDir;
}

public void setWorkdir(WorkDir workDir) {
this.workDir = workDir;
}

public void setTmcProjectDirectory(Path path) {
this.settings.setTmcProjectDirectory(path);
}

public HashMap<String, String> getProperties() {
// Loads properties from the global configuration file in .config/tmc-cli/
return this.properties;
}

public Boolean saveProperties() {
// Saves properties to the global configuration file in .config/tmc-cli/
return SettingsIo.saveProperties(properties);
}

public static boolean isWindows() {
String os = System.getProperty("os.name").toLowerCase();
return os.contains("windows");
}

public static int getTerminalWidth() {
String colEnv = System.getenv("COLUMNS");
if (colEnv != null && !colEnv.equals("")) {
// Determine the terminal width - this won't work on Windows
// Let's just hope our Windows users won't narrow their command prompt
// We'll also enforce a minimum size of 20 columns

return Math.max(Integer.parseInt(colEnv), 20);
} else {
return 70;
}
}

public CourseInfo createCourseInfo(Course course) {
return new CourseInfo(settings, course);
}

private void versionCheck() {
Map<String, String> properties = context.getProperties();
String previousTimestamp = properties.get(previousUpdateDateKey);
Date previous = null;

Expand All @@ -303,19 +160,21 @@ private void versionCheck() {
return;
}

TmcCliUpdater update = new TmcCliUpdater(io, getVersion(), isWindows());
TmcCliUpdater update = new TmcCliUpdater(io, EnvironmentUtil.getVersion(),
EnvironmentUtil.isWindows());
update.run();

long timestamp = now.getTime();
properties.put(previousUpdateDateKey, Long.toString(timestamp));
saveProperties();
context.saveProperties();
}

public Color.AnsiColor getColor(String context) {
String propertyValue = this.properties.get(context);
//TODO rename this as getColorProperty
public Color.AnsiColor getColor(String propertyName) {
String propertyValue = context.getProperties().get(propertyName);
Color.AnsiColor color = Color.getColor(propertyValue);
if (color == null) {
switch (context) {
switch (propertyName) {
case "progressbar-left": return Color.AnsiColor.ANSI_CYAN;
case "progressbar-right": return Color.AnsiColor.ANSI_CYAN;
case "testresults-left": return Color.AnsiColor.ANSI_GREEN;
Expand Down
Loading