progress
This commit is contained in:
parent
21578c9877
commit
97cfd233a6
11 changed files with 237 additions and 203 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -36,4 +36,4 @@ nimcache/
|
|||
|
||||
# Exclude project files
|
||||
!config.nims
|
||||
!dashinit.nimble
|
||||
!dashinit.nimble
|
||||
|
|
|
@ -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")
|
|
@ -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"
|
|
@ -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")
|
39
src/lib/environment.nim
Normal file
39
src/lib/environment.nim
Normal file
|
@ -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)
|
|
@ -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")
|
||||
|
|
34
src/lib/utils.nim
Normal file
34
src/lib/utils.nim
Normal file
|
@ -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)
|
62
src/main.nim
62
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()
|
||||
|
|
|
@ -1,5 +1,39 @@
|
|||
# dashinit Configuration File
|
||||
|
||||
[general]
|
||||
[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"
|
||||
|
||||
# # 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
|
|
@ -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!"
|
||||
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."
|
|
@ -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!"
|
||||
let endTime = cpuTime()
|
||||
let elapsedTime = (endTime - startTime) * 1000
|
||||
let roundElapsedTime = formatFloat(elapsedTime, precision=2)
|
||||
echo "Done! (", roundElapsedTime, "ms)"
|
Loading…
Reference in a new issue