From 21578c987749ec7e0946b0c54952cac5b8cbf036 Mon Sep 17 00:00:00 2001 From: Sangelo Date: Sun, 15 Oct 2023 18:22:33 +0200 Subject: [PATCH] Progress --- config.nims | 1 + dashinit.nimble | 4 +- src/handlers/configHandler.nim | 2 +- src/handlers/dlTemplateHandler.nim | 65 ++++++++++++++++ src/handlers/initialRunHandler.nim | 83 +++++++++++++++++++++ src/lib/downloader.nim | 21 ++++++ src/lib/progress.nim | 20 +++++ src/lib/styledOut.nim | 21 ++++++ src/main.nim | 13 +++- src/resources/{ => config}/config.toml | 0 src/resources/{ => config}/config.toml.new | 11 ++- src/resources/templates/default/README.md | 0 src/resources/templates/default/config.toml | 14 ++++ src/subcommands/init.nim | 21 ++++-- test/test | 0 test/testdir/test1 | 0 16 files changed, 258 insertions(+), 18 deletions(-) create mode 100644 src/handlers/dlTemplateHandler.nim create mode 100644 src/handlers/initialRunHandler.nim create mode 100644 src/lib/downloader.nim create mode 100644 src/lib/progress.nim create mode 100644 src/lib/styledOut.nim rename src/resources/{ => config}/config.toml (100%) rename src/resources/{ => config}/config.toml.new (84%) create mode 100644 src/resources/templates/default/README.md create mode 100644 src/resources/templates/default/config.toml create mode 100644 test/test create mode 100644 test/testdir/test1 diff --git a/config.nims b/config.nims index c90a672..d1ef13c 100644 --- a/config.nims +++ b/config.nims @@ -2,6 +2,7 @@ # Set some common options switch("d", "release") +switch("d", "ssl") switch("hints", "off") # Helper procs to abstract away OS-specific commands diff --git a/dashinit.nimble b/dashinit.nimble index 23f166d..b3165aa 100644 --- a/dashinit.nimble +++ b/dashinit.nimble @@ -9,4 +9,6 @@ bin = @["dashinit"] # Dependencies -requires "nim >= 2.0.0" \ No newline at end of file +requires "nim >= 2.0.0" +requires "parsetoml >= 0.7.1" +requires "downit >= 0.2.2" \ No newline at end of file diff --git a/src/handlers/configHandler.nim b/src/handlers/configHandler.nim index cfe598f..5f2feb7 100644 --- a/src/handlers/configHandler.nim +++ b/src/handlers/configHandler.nim @@ -10,7 +10,7 @@ proc createConfigFile*() = when defined(release): # Determine the operating system when defined(windows): - configPath = os.getHomeDir() / "dashinit" / "config.toml" + configPath = os.getHomeDir() / "AppData" / "Roaming" / "dashinit" / "config.toml" else: configPath = os.getHomeDir() / ".config" / "dashinit" / "config.toml" else: diff --git a/src/handlers/dlTemplateHandler.nim b/src/handlers/dlTemplateHandler.nim new file mode 100644 index 0000000..9bc6cab --- /dev/null +++ b/src/handlers/dlTemplateHandler.nim @@ -0,0 +1,65 @@ +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 new file mode 100644 index 0000000..a09fc1b --- /dev/null +++ b/src/handlers/initialRunHandler.nim @@ -0,0 +1,83 @@ +# src/handlers/initialRunHandler.nim + +import os, osproc +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) + +# Ensure the templates directory exists +proc ensureTemplatesDirExists() = + if not dirExists(templateBaseDir): + try: + os.createDir(templateBaseDir) + except: + styledPrint("Failed to create templates directory at " & $templateBaseDir, error) + +# Ensure the config file exists +proc ensureConfigFileExists() = + + # Create the directory if it doesn't exist + let dir = confBaseDir + if not dir.dirExists(): + try: + dir.createDir() + except: + styledPrint("Failed to create config directory at " & $confBaseDir, error) + + # Write the template config to the determined path + if not configPath.fileExists(): + try: + writeFile(configPath, dashinitConfig) + except: + styledPrint("Failed to create config file at " & $configPath, error) + +# Ensure the cache directory exists +proc ensureCacheDirExists() = + # Create the directory if it doesn't exist + let dir = cacheBaseDir + if not dir.dirExists(): + try: + dir.createDir() + except: + styledPrint("Failed to create cache directory at " & $cacheBaseDir, error) + +# Ensure all initial directories and files are set up +proc initialSetup*() = + ensureTemplatesDirExists() + ensureConfigFileExists() + ensureCacheDirExists() diff --git a/src/lib/downloader.nim b/src/lib/downloader.nim new file mode 100644 index 0000000..27d2e1b --- /dev/null +++ b/src/lib/downloader.nim @@ -0,0 +1,21 @@ +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/progress.nim b/src/lib/progress.nim new file mode 100644 index 0000000..939e5e6 --- /dev/null +++ b/src/lib/progress.nim @@ -0,0 +1,20 @@ +import strutils, terminal, system +import os + +proc printProgressBar*(progress: int, msg: string) = + hideCursor() + const totalWidth = 50 + 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(fgCyan, "] ") + stdout.styledWrite(fgYellow, $(int(progress.float)), "%") + stdout.styledWrite(" ", msg & "\r") + flushFile(stdout) + showCursor() + +for i in 0..100: + printProgressBar(i, "Time consuming task...") + sleep(100) diff --git a/src/lib/styledOut.nim b/src/lib/styledOut.nim new file mode 100644 index 0000000..47a7f08 --- /dev/null +++ b/src/lib/styledOut.nim @@ -0,0 +1,21 @@ +import terminal + +type + StyleKind* = enum + info, warning, error, success, debug + +proc styledPrint*(msg: string, kind: StyleKind) = + case kind + of info: + styledEcho styleBright, fgBlue, "Info: ", resetStyle, fgBlue, msg, resetStyle + of warning: + styledEcho styleBright, fgYellow, "Warning: ", resetStyle, fgYellow, msg, resetStyle + of error: + styledEcho styleBright, fgRed, "Error: ", resetStyle, fgRed, msg, resetStyle + of debug: + styledEcho styleBright, styleDim, "Debug: ", resetStyle, styleDim, msg, resetStyle + of success: + styledEcho styleBright, fgGreen, msg, resetStyle + +proc styledPrintln*(msg: string, kind: StyleKind) = + styledPrint(msg & "\n", kind) diff --git a/src/main.nim b/src/main.nim index a12a718..9ff34d0 100644 --- a/src/main.nim +++ b/src/main.nim @@ -2,11 +2,12 @@ import os, strutils import subcommands/help import subcommands/init -import handlers/configHandler +import handlers/initialRunHandler +import lib/styledOut proc main() = - # Create the config file if it doesn't exist already - createConfigFile() + # Initialise the program on first run + initialSetup() # Check for arguments and initialise directly if none are found let args = commandLineParams() @@ -22,6 +23,12 @@ proc main() = 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) else: echo "Unknown argument '", subcommand, "'. Use 'help' for available commands." diff --git a/src/resources/config.toml b/src/resources/config/config.toml similarity index 100% rename from src/resources/config.toml rename to src/resources/config/config.toml diff --git a/src/resources/config.toml.new b/src/resources/config/config.toml.new similarity index 84% rename from src/resources/config.toml.new rename to src/resources/config/config.toml.new index 235fe4b..3e55aa5 100644 --- a/src/resources/config.toml.new +++ b/src/resources/config/config.toml.new @@ -1,13 +1,12 @@ # dashinit Configuration File -[general] -# Where to download templates from -template_repo = "https://gitpot.dev/dashinit/templates" - +[template] # The default template to be used when initialising -default_template = "default" +default = "default" + +# Which meta repository to use as a source for templates +repository = "https://gitpot.dev/dashinit/templates" -[templates] # Allow user scripts to be executed allow_scripts = false diff --git a/src/resources/templates/default/README.md b/src/resources/templates/default/README.md new file mode 100644 index 0000000..e69de29 diff --git a/src/resources/templates/default/config.toml b/src/resources/templates/default/config.toml new file mode 100644 index 0000000..a7abb3f --- /dev/null +++ b/src/resources/templates/default/config.toml @@ -0,0 +1,14 @@ +[template] +name = "Default" +version = "0.1.0" +authors = [ + "Dashinit Contributors", + "Sangelo" +] +links = [ + "https://gitpot.dev/dashinit/templates/src/branch/main/default/README.md" +] + +[automation] +enabled = true +script = "./scripts/main.sh" \ No newline at end of file diff --git a/src/subcommands/init.nim b/src/subcommands/init.nim index 88e14fd..ae68e0d 100644 --- a/src/subcommands/init.nim +++ b/src/subcommands/init.nim @@ -1,26 +1,31 @@ import os, strutils, strformat +import ../lib/styledOut # import parsetoml # Define how to handle failed copies proc copyFile(src, dest: string): bool = try: os.copyFile(src, dest) - echo "Successfully copied ", src, " to ", dest + styledPrint(&"Successfully copied {src} to {dest}", success) return true except: - echo "Failed to copy ", src, " to ", dest + styledPrint(&"Failed to copy {src} to {dest}", error) return false # Define how to handle failed directory creations proc createDir(dir: string): bool = try: os.createDir(dir) - echo "Successfully created ", dir + styledPrint(&"Successfully created {dir}", success) return true except: - echo "Failed to create ", dir + styledPrint(&"Failed to create {dir}", error) return false +proc initialiseProject() = + discard createDir("testdir") + discard copyFile("test", "testdir/test1") + # Define how to handle configuring a git repo proc configureGitRepo(gitRemote, gitBranch: string) = let setupGitRepo = execShellCmd(&"git remote add origin {gitRemote}") @@ -42,18 +47,20 @@ proc init*() = for entry in walkDir("."): count += 1 # If there are files, ask for confirmation, otherwise continue. - if not count == 0: - echo "This directory is not empty." - echo "Continue initialising? [y/N]" + if count > 0: + styledPrint("This directory is not empty.", warning) + stdout.write("Continue initialising? [y/N] ") var input = stdin.readLine() case input.toLower of "yes", "y", "z", "j": echo "Initialising non-empty directory..." + initialiseProject() else: echo "Cancelling..." quit 0 else: echo "Initialising..." + initialiseProject() # Handle -g parameter for git repos. if "-g" in (commandLineParams()): diff --git a/test/test b/test/test new file mode 100644 index 0000000..e69de29 diff --git a/test/testdir/test1 b/test/testdir/test1 new file mode 100644 index 0000000..e69de29