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
|
||||
switch("d", "release")
|
||||
switch("d", "ssl")
|
||||
switch("hints", "off")
|
||||
|
||||
# Helper procs to abstract away OS-specific commands
|
||||
|
|
|
@ -9,4 +9,6 @@ bin = @["dashinit"]
|
|||
|
||||
# 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):
|
||||
# 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:
|
||||
|
|
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 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."
|
||||
|
||||
|
|
|
@ -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
|
||||
|
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 ../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()):
|
||||
|
|
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