This commit is contained in:
Sangelo 2023-12-02 01:26:06 +01:00
parent 21578c9877
commit 97cfd233a6
11 changed files with 237 additions and 203 deletions

2
.gitignore vendored
View file

@ -36,4 +36,4 @@ nimcache/
# Exclude project files
!config.nims
!dashinit.nimble
!dashinit.nimble

View file

@ -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")

View file

@ -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"

View file

@ -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
View 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)

View file

@ -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
View 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)

View file

@ -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()

View file

@ -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

View file

@ -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."

View file

@ -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)"