Progress
This commit is contained in:
parent
06b129bcbf
commit
21578c9877
16 changed files with 258 additions and 18 deletions
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
# Set some common options
|
# Set some common options
|
||||||
switch("d", "release")
|
switch("d", "release")
|
||||||
|
switch("d", "ssl")
|
||||||
switch("hints", "off")
|
switch("hints", "off")
|
||||||
|
|
||||||
# Helper procs to abstract away OS-specific commands
|
# Helper procs to abstract away OS-specific commands
|
||||||
|
|
|
@ -9,4 +9,6 @@ bin = @["dashinit"]
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
|
||||||
requires "nim >= 2.0.0"
|
requires "nim >= 2.0.0"
|
||||||
|
requires "parsetoml >= 0.7.1"
|
||||||
|
requires "downit >= 0.2.2"
|
|
@ -10,7 +10,7 @@ proc createConfigFile*() =
|
||||||
when defined(release):
|
when defined(release):
|
||||||
# Determine the operating system
|
# Determine the operating system
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
configPath = os.getHomeDir() / "dashinit" / "config.toml"
|
configPath = os.getHomeDir() / "AppData" / "Roaming" / "dashinit" / "config.toml"
|
||||||
else:
|
else:
|
||||||
configPath = os.getHomeDir() / ".config" / "dashinit" / "config.toml"
|
configPath = os.getHomeDir() / ".config" / "dashinit" / "config.toml"
|
||||||
else:
|
else:
|
||||||
|
|
65
src/handlers/dlTemplateHandler.nim
Normal file
65
src/handlers/dlTemplateHandler.nim
Normal file
|
@ -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")
|
83
src/handlers/initialRunHandler.nim
Normal file
83
src/handlers/initialRunHandler.nim
Normal file
|
@ -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()
|
21
src/lib/downloader.nim
Normal file
21
src/lib/downloader.nim
Normal file
|
@ -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")
|
20
src/lib/progress.nim
Normal file
20
src/lib/progress.nim
Normal file
|
@ -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)
|
21
src/lib/styledOut.nim
Normal file
21
src/lib/styledOut.nim
Normal file
|
@ -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)
|
13
src/main.nim
13
src/main.nim
|
@ -2,11 +2,12 @@
|
||||||
import os, strutils
|
import os, strutils
|
||||||
import subcommands/help
|
import subcommands/help
|
||||||
import subcommands/init
|
import subcommands/init
|
||||||
import handlers/configHandler
|
import handlers/initialRunHandler
|
||||||
|
import lib/styledOut
|
||||||
|
|
||||||
proc main() =
|
proc main() =
|
||||||
# Create the config file if it doesn't exist already
|
# Initialise the program on first run
|
||||||
createConfigFile()
|
initialSetup()
|
||||||
|
|
||||||
# Check for arguments and initialise directly if none are found
|
# Check for arguments and initialise directly if none are found
|
||||||
let args = commandLineParams()
|
let args = commandLineParams()
|
||||||
|
@ -22,6 +23,12 @@ proc main() =
|
||||||
displayHelp()
|
displayHelp()
|
||||||
of "init":
|
of "init":
|
||||||
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:
|
else:
|
||||||
echo "Unknown argument '", subcommand, "'. Use 'help' for available commands."
|
echo "Unknown argument '", subcommand, "'. Use 'help' for available commands."
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
# dashinit Configuration File
|
# dashinit Configuration File
|
||||||
|
|
||||||
[general]
|
[template]
|
||||||
# Where to download templates from
|
|
||||||
template_repo = "https://gitpot.dev/dashinit/templates"
|
|
||||||
|
|
||||||
# The default template to be used when initialising
|
# 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 user scripts to be executed
|
||||||
allow_scripts = false
|
allow_scripts = false
|
||||||
|
|
0
src/resources/templates/default/README.md
Normal file
0
src/resources/templates/default/README.md
Normal file
14
src/resources/templates/default/config.toml
Normal file
14
src/resources/templates/default/config.toml
Normal file
|
@ -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"
|
|
@ -1,26 +1,31 @@
|
||||||
import os, strutils, strformat
|
import os, strutils, strformat
|
||||||
|
import ../lib/styledOut
|
||||||
# import parsetoml
|
# import parsetoml
|
||||||
|
|
||||||
# Define how to handle failed copies
|
# Define how to handle failed copies
|
||||||
proc copyFile(src, dest: string): bool =
|
proc copyFile(src, dest: string): bool =
|
||||||
try:
|
try:
|
||||||
os.copyFile(src, dest)
|
os.copyFile(src, dest)
|
||||||
echo "Successfully copied ", src, " to ", dest
|
styledPrint(&"Successfully copied {src} to {dest}", success)
|
||||||
return true
|
return true
|
||||||
except:
|
except:
|
||||||
echo "Failed to copy ", src, " to ", dest
|
styledPrint(&"Failed to copy {src} to {dest}", error)
|
||||||
return false
|
return false
|
||||||
|
|
||||||
# Define how to handle failed directory creations
|
# Define how to handle failed directory creations
|
||||||
proc createDir(dir: string): bool =
|
proc createDir(dir: string): bool =
|
||||||
try:
|
try:
|
||||||
os.createDir(dir)
|
os.createDir(dir)
|
||||||
echo "Successfully created ", dir
|
styledPrint(&"Successfully created {dir}", success)
|
||||||
return true
|
return true
|
||||||
except:
|
except:
|
||||||
echo "Failed to create ", dir
|
styledPrint(&"Failed to create {dir}", error)
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
proc initialiseProject() =
|
||||||
|
discard createDir("testdir")
|
||||||
|
discard copyFile("test", "testdir/test1")
|
||||||
|
|
||||||
# Define how to handle configuring a git repo
|
# Define how to handle configuring a git repo
|
||||||
proc configureGitRepo(gitRemote, gitBranch: string) =
|
proc configureGitRepo(gitRemote, gitBranch: string) =
|
||||||
let setupGitRepo = execShellCmd(&"git remote add origin {gitRemote}")
|
let setupGitRepo = execShellCmd(&"git remote add origin {gitRemote}")
|
||||||
|
@ -42,18 +47,20 @@ proc init*() =
|
||||||
for entry in walkDir("."):
|
for entry in walkDir("."):
|
||||||
count += 1
|
count += 1
|
||||||
# If there are files, ask for confirmation, otherwise continue.
|
# If there are files, ask for confirmation, otherwise continue.
|
||||||
if not count == 0:
|
if count > 0:
|
||||||
echo "This directory is not empty."
|
styledPrint("This directory is not empty.", warning)
|
||||||
echo "Continue initialising? [y/N]"
|
stdout.write("Continue initialising? [y/N] ")
|
||||||
var input = stdin.readLine()
|
var input = stdin.readLine()
|
||||||
case input.toLower
|
case input.toLower
|
||||||
of "yes", "y", "z", "j":
|
of "yes", "y", "z", "j":
|
||||||
echo "Initialising non-empty directory..."
|
echo "Initialising non-empty directory..."
|
||||||
|
initialiseProject()
|
||||||
else:
|
else:
|
||||||
echo "Cancelling..."
|
echo "Cancelling..."
|
||||||
quit 0
|
quit 0
|
||||||
else:
|
else:
|
||||||
echo "Initialising..."
|
echo "Initialising..."
|
||||||
|
initialiseProject()
|
||||||
|
|
||||||
# Handle -g parameter for git repos.
|
# Handle -g parameter for git repos.
|
||||||
if "-g" in (commandLineParams()):
|
if "-g" in (commandLineParams()):
|
||||||
|
|
0
test/test
Normal file
0
test/test
Normal file
0
test/testdir/test1
Normal file
0
test/testdir/test1
Normal file
Loading…
Reference in a new issue