From 97cfd233a61fc17e325f121d2dc9e5508df25fc2 Mon Sep 17 00:00:00 2001 From: Sangelo Date: Sat, 2 Dec 2023 01:26:06 +0100 Subject: [PATCH] progress --- .gitignore | 2 +- src/handlers/dlTemplateHandler.nim | 65 --------------------------- src/handlers/initialRunHandler.nim | 45 +++---------------- src/lib/downloader.nim | 21 --------- src/lib/environment.nim | 39 ++++++++++++++++ src/lib/progress.nim | 4 +- src/lib/utils.nim | 34 ++++++++++++++ src/main.nim | 62 ++++++++++++++----------- src/resources/config/config.toml | 38 +++++++++++++++- src/subcommands/help.nim | 58 +++++++++++++++++------- src/subcommands/init.nim | 72 ++++++++++++++++-------------- 11 files changed, 237 insertions(+), 203 deletions(-) delete mode 100644 src/handlers/dlTemplateHandler.nim delete mode 100644 src/lib/downloader.nim create mode 100644 src/lib/environment.nim create mode 100644 src/lib/utils.nim diff --git a/.gitignore b/.gitignore index 83b3956..45e30c4 100644 --- a/.gitignore +++ b/.gitignore @@ -36,4 +36,4 @@ nimcache/ # Exclude project files !config.nims -!dashinit.nimble \ No newline at end of file +!dashinit.nimble diff --git a/src/handlers/dlTemplateHandler.nim b/src/handlers/dlTemplateHandler.nim deleted file mode 100644 index 9bc6cab..0000000 --- a/src/handlers/dlTemplateHandler.nim +++ /dev/null @@ -1,65 +0,0 @@ -import strutils, httpclient, streams, zippy/tarballs, async, os, parsetoml -import ../lib/progress - -const - defaultMetaRepo = "https://gitpot.dev/dashinit/templates" - configPath = "~/.config/dashinit/config.toml" - templatesDir = "~/.local/share/dashinit/templates/" - tempDir = templatesDir / ".tmp/" - -# Fetch meta-repository from the config file -proc getMetaRepoFromConfig(): string = - if fileExists(expandFilename(configPath)): - let tomlData = parseFile(expandFilename(configPath)) - if "template" in tomlData and "repository" in tomlData["template"]: - return tomlData["template"]["repository"].getStr() - return defaultMetaRepo - -proc downloadFile*(url: string, filename: string) {.async.} = - var downloaded = 0 - - proc onProgressChanged(total, progress: BiggestInt, speed: float64) = - let downloadProgress = (progress.float / total.float) * 100 - printProgressBar(int(downloadProgress), "Downloading file...") - - var client = newHttpClient() - client.onProgressChanged = onProgressChanged - let content = await client.getContent(url) - writeFile(filename, content) - - # Ensure the progress bar reaches 100% at the end - printProgressBar(100, "Download complete!") - -proc downloadTemplate*(package: string, repo: string = getMetaRepoFromConfig(), release: string = "latest") = - # Construct the tar URL - let tarUrl = if release == "latest": - repo & "/" & package & "/archive/main.tar.gz" - else: - repo & "/" & package & "/archive/" & release & ".tar.gz" - - # Ensure temporary directory exists - if not dirExists(expandFilename(tempDir)): - createDir(expandFilename(tempDir)) - - let tarFilePath = expandFilename(tempDir) / package / ".temp.tar.gz" - - # Use the re-implemented downloadFile procedure - waitFor downloadFile(tarUrl, tarFilePath) - - # Open the tarball from the saved file for extraction - let tarFile = open(tarFilePath) - for entry in tarFile: - let outputPath = expandFilename(tempDir) / entry.name - if entry.kind == ekDirectory: - createDir(outputPath) - else: - writeFile(outputPath, entry.contents) - - # Optionally delete the tarball file afterward - removeFile(tarFilePath) - - # After extraction, move the files to the correct directory (parent of .tmp) - moveDir(expandFilename(tempDir / package), expandFilename(templatesDir / package)) - removeDir(expandFilename(tempDir)) # Clear the temporary directory - -# Usage: downloadTemplate("default") diff --git a/src/handlers/initialRunHandler.nim b/src/handlers/initialRunHandler.nim index a09fc1b..09da744 100644 --- a/src/handlers/initialRunHandler.nim +++ b/src/handlers/initialRunHandler.nim @@ -1,44 +1,9 @@ # src/handlers/initialRunHandler.nim +# TODO fix messed up initial config creation -import os, osproc +import os import ../lib/styledOut - -# Path of the default dashinit config -const dashinitConfig = staticRead("../resources/config/config.toml") - -let roamingAppData = getEnv("APPDATA") -let localAppData = getEnv("LOCALAPPDATA") -let homeDir = os.getHomeDir() - -# Base directory containing templates and other files -let dashinitBaseDir* = if hostOS == "windows": - roamingAppData / "dashinit" -else: - homeDir / ".local" / "share" / "dashinit" - -# Dashinit config directory containing the config files -let confBaseDir* = if hostOs == "windows": - roamingAppData / "dashinit" -else: - homeDir / ".config" / "dashinit" - -# Cache directory containing donwloaded templates used as cache -let cacheBaseDir* = if hostOs == "windows": - localAppData / "dashinit" -else: - homeDir / ".cache" / "dashinit" - -# Get the template directory path based on the OS -let templateBaseDir* = dashinitBaseDir / "templates" - -# Get the config file path based on the OS -let configPath* = confBaseDir / "config.toml" - -let contentsConf = execProcess("ls -l " & $confBaseDir) -let contentsLocal = execProcess("ls -l " & $dashinitBaseDir) - -styledPrint("Contents of config path: " & $contentsConf, debug) -styledPrint("Contents of local path: " & $contentsLocal, debug) +import ../lib/environment # Ensure the templates directory exists proc ensureTemplatesDirExists() = @@ -78,6 +43,10 @@ proc ensureCacheDirExists() = # Ensure all initial directories and files are set up proc initialSetup*() = + echo "1" ensureTemplatesDirExists() + echo "2" ensureConfigFileExists() + echo "3" ensureCacheDirExists() + echo "done" \ No newline at end of file diff --git a/src/lib/downloader.nim b/src/lib/downloader.nim deleted file mode 100644 index 27d2e1b..0000000 --- a/src/lib/downloader.nim +++ /dev/null @@ -1,21 +0,0 @@ -import tables, strutils, downit, ./progress - -proc downloadFile*(url: string, path: string) = - var client = newHttpClient() - try: - let response = client.get(url) - let totalSize = parseInt(response.headers.getOrDefault("Content-Length", "-1")) - var downloadedSize = 0 - let file = open(path, fmWrite) - try: - for chunk in response.bodyStream: - file.write(chunk) - downloadedSize += chunk.len - let progress = (downloadedSize.float / totalSize.float) * 100 - printProgressBar(int(progress), "Downloading to " & path & "...") - finally: - file.close() - finally: - client.close() - -downloadFile("https://files.sangelo.space/whoogle-yacht/whoogle-yacht.json", "whoogle-yacht.json") diff --git a/src/lib/environment.nim b/src/lib/environment.nim new file mode 100644 index 0000000..684f41c --- /dev/null +++ b/src/lib/environment.nim @@ -0,0 +1,39 @@ +import os + +# Path of the default dashinit config +const dashinitConfig* = staticRead("../resources/config/config.toml") + +let roamingAppData* = getEnv("APPDATA") +let localAppData* = getEnv("LOCALAPPDATA") +let homeDir* = os.getHomeDir() + +# Base directory containing templates and other files +let dashinitBaseDir* = if hostOS == "windows": + roamingAppData / "dashinit" +else: + homeDir / ".local" / "share" / "dashinit" + +# Dashinit config directory containing the config files +let confBaseDir* = if hostOs == "windows": + roamingAppData / "dashinit" +else: + homeDir / ".config" / "dashinit" + +# Cache directory containing donwloaded templates used as cache +let cacheBaseDir* = if hostOs == "windows": + localAppData / "dashinit" +else: + homeDir / ".cache" / "dashinit" + +# Get the template directory path based on the OS +let templateBaseDir* = dashinitBaseDir / "templates" + +# Get the config file path based on the OS +let configPath* = confBaseDir / "config.toml" + + +# debug +# let contentsConf = execProcess("ls -l " & $confBaseDir) +# let contentsLocal = execProcess("ls -l " & $dashinitBaseDir) +# styledPrint("Contents of config path: " & $contentsConf, debug) +# styledPrint("Contents of local path: " & $contentsLocal, debug) \ No newline at end of file diff --git a/src/lib/progress.nim b/src/lib/progress.nim index 939e5e6..806730f 100644 --- a/src/lib/progress.nim +++ b/src/lib/progress.nim @@ -7,8 +7,8 @@ proc printProgressBar*(progress: int, msg: string) = let filledWidth = int(progress.float * totalWidth / 100) let emptyWidth = totalWidth - filledWidth stdout.styledWrite(fgCyan, "[") - stdout.styledWrite(fgGreen, "█".repeat(filledWidth)) - stdout.styledWrite(fgWhite, "░".repeat(emptyWidth)) + stdout.styledWrite(fgGreen, "#".repeat(filledWidth)) + stdout.styledWrite(fgWhite, ".".repeat(emptyWidth)) stdout.styledWrite(fgCyan, "] ") stdout.styledWrite(fgYellow, $(int(progress.float)), "%") stdout.styledWrite(" ", msg & "\r") diff --git a/src/lib/utils.nim b/src/lib/utils.nim new file mode 100644 index 0000000..58b61d6 --- /dev/null +++ b/src/lib/utils.nim @@ -0,0 +1,34 @@ +import os, strformat +import ../lib/styledOut + +proc copyFile*(src, dest: string): bool = + try: + os.copyFile(src, dest) + # styledPrint(&"Successfully copied {src} to {dest}", success) + except: + styledPrint(&"Failed to copy {src} to {dest}", error) + +proc copyDir*(src, dest: string) = + if not dirExists(dest): + createDir(dest) + + for kind, path in walkDir(src, relative=false): + let relativePath = path.relativePath(src) + let destPath = joinPath(dest, relativePath) + + if kind == pcFile: + discard copyFile(path, destPath) + elif kind == pcDir and path != src: + if not dirExists(destPath): + createDir(destPath) + copyDir(path, destPath) + +proc copyRecursive*(src, dest: string) = + copyDir(src, dest) + +# proc createDir(dir: string): bool = +# try: +# os.createDir(dir) +# # styledPrint(&"Successfully created {dir}", success) +# except: +# styledPrint(&"Failed to create {dir}", error) \ No newline at end of file diff --git a/src/main.nim b/src/main.nim index 9ff34d0..22af78d 100644 --- a/src/main.nim +++ b/src/main.nim @@ -1,36 +1,46 @@ -# src/main.nim -import os, strutils -import subcommands/help -import subcommands/init +import os, strutils, tables +import subcommands/help, subcommands/init import handlers/initialRunHandler import lib/styledOut -proc main() = - # Initialise the program on first run - initialSetup() +type + CommandHandler = proc(args: seq[string]) - # Check for arguments and initialise directly if none are found - let args = commandLineParams() - if args.len == 0: - init() - return +var commandRegistry = initTable[string, CommandHandler]() - let subcommand = args[0].toLower() ## turn arguments into lowercase +proc registerCommand(name: string, handler: CommandHandler) = + commandRegistry[name] = handler - # Check for arguments and execute proper command, if argument is invalid stop the program - case subcommand - of "help": - displayHelp() - of "init": - init() - of "--debug-colors": - styledPrintln("This is an info message.", info) - styledPrintln("This is a warning message.", warning) - styledPrintln("This is an error message.", error) - styledPrintln("This is a success message.", success) - styledPrint("This is a debug message.", debug) +proc helpWrapper(args: seq[string]) = + let helpMsg = if args.len > 0: args[0] else: "main" + help.displayHelp(helpMsg, args) + +proc processCommands(args: seq[string]) = + if args.len > 0: + let cmd = args[0].toLower() + let subArgs = args[1..^1] + if cmd in commandRegistry: + commandRegistry[cmd](subArgs) + else: + echo "Unknown command: '", cmd, "'. Use 'help' for available commands." else: - echo "Unknown argument '", subcommand, "'. Use 'help' for available commands." + commandRegistry["init"](@[]) + +proc colorDebug() = + styledPrintln("This is an info message.", info) + styledPrintln("This is a warning message.", warning) + styledPrintln("This is an error message.", error) + styledPrintln("This is a success message.", success) + styledPrint("This is a debug message.", debug) + +# Register commands +registerCommand("help", helpWrapper) +registerCommand("init", init.init) + +proc main() = + initialRunHandler.initialSetup() # Initialise the program on first run + let args = commandLineParams() + processCommands(args) when isMainModule: main() diff --git a/src/resources/config/config.toml b/src/resources/config/config.toml index cc27ee7..52d0bd6 100644 --- a/src/resources/config/config.toml +++ b/src/resources/config/config.toml @@ -1,5 +1,39 @@ # dashinit Configuration File -[general] +[template] # The default template to be used when initialising -default_template = "default" \ No newline at end of file +default = "default" + +# # Which meta repository to use as a source for templates +# repository = "https://gitpot.dev/dashinit/templates" + +# # Allow user scripts to be executed +# allow_scripts = false + +# # If allow_scripts is set to false, these scripts will still be executable +# script_whitelist = [ +# "default/default.sh" +# # "template/script.sh", +# # "~/.local/share/dashinit/scripts/script.sh" # full paths are also possible +# ] + +# [updates] +# # Check for updates periodically. Disabled by default +# check = false + +# # Frequency to check for updates. (daily, weekly, monthly) +# # If an unrecognized value is provided, it defaults to 'weekly' +# frequency = "weekly" + +# [logs] +# # Whether logs are enabled or not +# enabled = false + +# # Specify log level (info, warning, error, debug) +# level = "info" + +# # Where the logs should be stored +# path = "~/.local/share/dashinit/logs" + +# # Maximum log size in MB before a new log gets created +# max_size = 10 \ No newline at end of file diff --git a/src/subcommands/help.nim b/src/subcommands/help.nim index 7545126..8354f24 100644 --- a/src/subcommands/help.nim +++ b/src/subcommands/help.nim @@ -18,24 +18,52 @@ var commands: seq[Command] = @[ ] var options: seq[Option] = @[ - ("-h", "Displays this help message.") + ("-h, --help", "Displays this help message.") ] -proc displayHelp*() = - echo "dashinit - a powerful templating tool" +proc displayHelp*(helpMsg: string, args: seq[string] = @[]) = + case helpMsg + of "init": + var initOptions: seq[Option] = @[ + ("-h, --help", "Displays this help message."), + ("-g, --git", "Initialises a git repository."), + ("-v\t", "Verbose output.") + ] - echo "\nUsage:" - styledEcho styleBright, " dashinit", resetStyle, " [subcommand] [arguments]" + echo "dashinit - a powerful templating tool" - echo "\nSubcommands:" - for command in commands: - styledEcho " ", styleBright, command.cmd, resetStyle, " \t", command.desc + styledEcho "Subcommand: ", styleBright, "init" - echo "\nOptions:" - for option in options: - styledEcho " ", styleBright, option.arg, resetStyle, " \t", option.desc + echo "\nUsage:" + styledEcho styleBright, " dashinit", resetStyle, " [subcommand] [arguments]" - echo "\nExamples:" - echo " ", "dashinit", "\t\t\t", "Initialises using default settings." - echo " ", "dashinit template -h", "\t\t", "Shows the help menu for the template subcommand." - # styledEcho styleBright, fgGreen, "[PASS]", resetStyle, fgGreen, " Yay!" \ No newline at end of file + echo "\nOptions:" + for option in initOptions: + styledEcho " ", styleBright, option.arg, resetStyle, " \t", option.desc + + echo "\nExamples:" + echo " ", "dashinit", "\t\t\t", "Initialises using default settings." + echo " ", "dashinit init", "\t\t", "Initialises using default settings." + echo " ", "dashinit init -h", "\t\t", "Shows the help menu for the init subcommand." + echo " ", "dashinit init -g", "\t\t", "Initialises a git repository using a template." + + of "template": + echo "test" + + else: + echo "dashinit - a powerful templating tool" + + echo "\nUsage:" + styledEcho styleBright, " dashinit", resetStyle, " [subcommand] [arguments]" + + echo "\nSubcommands:" + for command in commands: + styledEcho " ", styleBright, command.cmd, resetStyle, " \t", command.desc + + echo "\nOptions:" + for option in options: + styledEcho " ", styleBright, option.arg, resetStyle, " \t", option.desc + + echo "\nExamples:" + echo " ", "dashinit", "\t\t\t", "Initialises using default settings." + echo " ", "dashinit template -h", "\t\t", "Shows the help menu for the template subcommand." \ No newline at end of file diff --git a/src/subcommands/init.nim b/src/subcommands/init.nim index ae68e0d..bedaee7 100644 --- a/src/subcommands/init.nim +++ b/src/subcommands/init.nim @@ -1,30 +1,32 @@ -import os, strutils, strformat -import ../lib/styledOut -# import parsetoml +import os, strutils, strformat, times +import ../lib/styledOut, ../lib/utils, ../lib/environment, ../subcommands/help +import parsetoml -# Define how to handle failed copies -proc copyFile(src, dest: string): bool = - try: - os.copyFile(src, dest) - styledPrint(&"Successfully copied {src} to {dest}", success) - return true - except: - styledPrint(&"Failed to copy {src} to {dest}", error) - return false +# start counting +let startTime = cpuTime() -# Define how to handle failed directory creations -proc createDir(dir: string): bool = - try: - os.createDir(dir) - styledPrint(&"Successfully created {dir}", success) - return true - except: - styledPrint(&"Failed to create {dir}", error) - return false +# # initialise variables +# var verbose = false; +# read config +let config = parsetoml.parseFile(configPath) +# let config = "test" + +let confTemplate = config["template"]["default"].getStr("default") # get template from config, otherwise use default +# let confTemplate = "test" +let selectedTemplate = templateBaseDir / confTemplate # set the selected template path (see environment.nim for templateBaseDir) +let currentDir = getCurrentDir() + +# subcommand help +type + Option = tuple[ + arg: string, + desc: string + ] + +# initialise project function proc initialiseProject() = - discard createDir("testdir") - discard copyFile("test", "testdir/test1") + copyRecursive(selectedTemplate, currentDir) # Define how to handle configuring a git repo proc configureGitRepo(gitRemote, gitBranch: string) = @@ -39,12 +41,14 @@ proc configureGitRepo(gitRemote, gitBranch: string) = else: echo &"Failed to set branch {gitBranch}" -#-------------------------------------------------------------------------------# +# Main logic +proc init*(args: seq[string]) = + if "-h" in args or "--help" in args or "help" in args: + displayHelp("init") + quit(0) -# Check for files in directory -proc init*() = var count = 0 - for entry in walkDir("."): + for entry in walkDir(currentDir): count += 1 # If there are files, ask for confirmation, otherwise continue. if count > 0: @@ -63,17 +67,17 @@ proc init*() = initialiseProject() # Handle -g parameter for git repos. - if "-g" in (commandLineParams()): + if "-g" in args or "--git" in args: let createdRepo = execShellCmd("git init") if createdRepo == 0: echo "Successfully initialised local git repository!" - echo "Would you like to configure it? [Y/n]" + stdout.write("Would you like to configure it? [Y/n] ") var input = stdin.readLine() case input.toLower of "yes", "y", "z", "j", "": - echo "Enter the git remote:" + stdout.write("Enter the git remote: ") let gitRemote = stdin.readLine() - echo "Enter your desired branch name:" + stdout.write("Enter your desired branch name: ") let gitBranch = stdin.readLine() echo "Configuring Git repo..." configureGitRepo(gitRemote, gitBranch) @@ -82,5 +86,7 @@ proc init*() = echo "Successfully created local git repository!" else: echo: "Failed creating local git repository." - - echo "Done!" \ No newline at end of file + let endTime = cpuTime() + let elapsedTime = (endTime - startTime) * 1000 + let roundElapsedTime = formatFloat(elapsedTime, precision=2) + echo "Done! (", roundElapsedTime, "ms)" \ No newline at end of file