mirror of
https://github.com/Kapendev/parin.git
synced 2025-04-26 04:59:54 +03:00
Replaced original setup script with a noby script.
This commit is contained in:
parent
b0180c6e55
commit
d71d6e0050
1 changed files with 243 additions and 99 deletions
|
@ -1,32 +1,26 @@
|
|||
#!/bin/env -S dmd -run
|
||||
|
||||
/// A helper script that automates the project setup.
|
||||
module noby;
|
||||
|
||||
import std.file;
|
||||
import std.path;
|
||||
import std.stdio;
|
||||
import std.string;
|
||||
import std.process;
|
||||
// [Noby Script]
|
||||
|
||||
enum assetsDir = buildPath(".", "assets");
|
||||
enum webDir = buildPath(".", "web");
|
||||
enum readmeFile = buildPath(".", "README.md");
|
||||
enum gitignoreFile = buildPath(".", ".gitignore");
|
||||
enum dubFile = buildPath(".", "dub.json");
|
||||
enum dubLockFile = buildPath(".", "dub.selections.json");
|
||||
enum assetsDir = join(".", "assets");
|
||||
enum webDir = join(".", "web");
|
||||
enum readmeFile = join(".", "README.md");
|
||||
enum gitFile = join(".", ".gitignore");
|
||||
enum dubFile = join(".", "dub.json");
|
||||
enum dubLockFile = join(".", "dub.selections.json");
|
||||
|
||||
enum readmeFileContent = "# Game Title
|
||||
enum readmeFileContent = `
|
||||
# Title
|
||||
|
||||
This game was created with [Parin](https://github.com/Kapendev/parin).
|
||||
|
||||
To compile the game, run:
|
||||
To compile the game, run: ...
|
||||
`[1 .. $];
|
||||
|
||||
```sh
|
||||
command arg1 arg2 ...
|
||||
```
|
||||
";
|
||||
|
||||
enum gitignoreFileContent = `.dub
|
||||
enum gitFileContent = `
|
||||
.dub
|
||||
game
|
||||
lib*
|
||||
test*
|
||||
|
@ -41,9 +35,10 @@ test*
|
|||
*.o
|
||||
*.obj
|
||||
*.lst
|
||||
`;
|
||||
`[1 .. $];
|
||||
|
||||
enum appFileContent = `import parin;
|
||||
enum appFileContent = `
|
||||
import parin;
|
||||
|
||||
void ready() {
|
||||
lockResolution(320, 180);
|
||||
|
@ -57,9 +52,10 @@ bool update(float dt) {
|
|||
void finish() { }
|
||||
|
||||
mixin runGame!(ready, update, finish);
|
||||
`;
|
||||
`[1 .. $];
|
||||
|
||||
enum dubFileContent = `{
|
||||
enum dubFileContent = `
|
||||
{
|
||||
"name" : "game",
|
||||
"description" : "A game made with Parin.",
|
||||
"authors" : ["Name"],
|
||||
|
@ -110,24 +106,19 @@ enum dubFileContent = `{
|
|||
}
|
||||
]
|
||||
}
|
||||
`;
|
||||
|
||||
/// Creates the assets and web folders inside the current folder.
|
||||
void makeFolders() {
|
||||
if (!exists(assetsDir)) std.file.mkdir(assetsDir);
|
||||
if (!exists(webDir)) std.file.mkdir(webDir);
|
||||
std.file.write(buildPath(assetsDir, ".gitkeep"), "");
|
||||
std.file.write(buildPath(webDir, ".gitkeep"), "");
|
||||
}
|
||||
`[1 .. $];
|
||||
|
||||
/// Creates the basic project setup of a parin project inside the current folder.
|
||||
void makeBasicSetup() {
|
||||
makeFolders();
|
||||
if (!exists(readmeFile)) std.file.write(readmeFile, readmeFileContent);
|
||||
if (!exists(gitignoreFile)) std.file.write(gitignoreFile, gitignoreFileContent);
|
||||
mkdir(assetsDir);
|
||||
mkdir(webDir);
|
||||
paste(join(assetsDir, ".gitkeep"), "");
|
||||
paste(join(webDir, ".gitkeep"), "");
|
||||
paste(readmeFile, readmeFileContent, true);
|
||||
paste(gitFile, gitFileContent, true);
|
||||
}
|
||||
|
||||
/// The setup code for simple standalone projects.
|
||||
/// The setup code for simple projects.
|
||||
int runSimpSetup(string[] args, bool isFirstRun) {
|
||||
makeBasicSetup();
|
||||
return 0;
|
||||
|
@ -135,83 +126,236 @@ int runSimpSetup(string[] args, bool isFirstRun) {
|
|||
|
||||
/// The setup code for dub projects.
|
||||
int runDubSetup(string[] args, bool isFirstRun) {
|
||||
// Create the backup copies.
|
||||
auto dubCopyFile = buildPath(".", "._dub_copy");
|
||||
auto dubLockCopyFile = buildPath(".", "._dub_lock_copy");
|
||||
if (exists(dubFile)) std.file.write(dubCopyFile, std.file.readText(dubFile));
|
||||
if (exists(dubLockFile)) std.file.write(dubLockCopyFile, std.file.readText(dubLockFile));
|
||||
// Create the basic files and folders.
|
||||
// NOTE: An empty dub project has a gitignore file and we don't want that file.
|
||||
if (isFirstRun && exists(gitignoreFile)) std.file.remove(gitignoreFile);
|
||||
makeBasicSetup();
|
||||
|
||||
// Find the app file.
|
||||
auto appDir = buildPath(".", "src");
|
||||
if (!exists(appDir)) appDir = buildPath(".", "source");
|
||||
auto appFile = buildPath(appDir, "main.d");
|
||||
if (!exists(appFile)) appFile = buildPath(appDir, "app.d");
|
||||
// Replace the app file content if needed.
|
||||
if (exists(appFile)) {
|
||||
if (isFirstRun) std.file.write(appFile, appFileContent);
|
||||
// Create basic stuff and clone the dub files.
|
||||
if (isFirstRun) {
|
||||
rm(gitFile);
|
||||
} else {
|
||||
std.file.write(appFile, appFileContent);
|
||||
clone(dubFile);
|
||||
clone(dubLockFile);
|
||||
}
|
||||
|
||||
// Get a yes or no from the user and download the raylib libraries if the user said yes.
|
||||
auto arg = (args.length != 0) ? args[0] : "?";
|
||||
while (true) {
|
||||
if (arg.length == 0) arg = "Y";
|
||||
foreach (c; "YyNn") {
|
||||
if (arg.length != 1) break;
|
||||
if (arg[0] == c) goto whileExit;
|
||||
}
|
||||
write("Would you like to download the raylib libraries? [Y/n] ");
|
||||
arg = readln().strip();
|
||||
}
|
||||
whileExit:
|
||||
if (arg == "Y" || arg == "y") {
|
||||
writeln("Downloading...");
|
||||
auto dub1 = spawnProcess(["dub", "add", "raylib-d", "--verror"]).wait();
|
||||
auto dub2 = spawnProcess(["dub", "run", "raylib-d:install", "--verror", "--", "-q", "-u=no"]).wait();
|
||||
makeBasicSetup();
|
||||
// Find the main file and replace its content.
|
||||
auto appDir = join(".", "src");
|
||||
if (!appDir.isX) appDir = join(".", "source");
|
||||
auto appFile = join(appDir, "main.d");
|
||||
if (!appFile.isX) appFile = join(appDir, "app.d");
|
||||
paste(appFile, appFileContent, !isFirstRun);
|
||||
// Get a yes or no and download the raylib libraries.
|
||||
IStr arg = readYesNo("Would you like to download raylib?", args.length > 1 ? args[1] : "?");
|
||||
if (arg.isYes) {
|
||||
echo("Downloading...");
|
||||
auto hasDubLockFileNow = dubLockFile.isX;
|
||||
auto dub1 = cmd("dub", "add", "raylib-d", "--verror");
|
||||
auto dub2 = cmd("dub", "run", "raylib-d:install", "--verror", "--", "-q", "-u=no");
|
||||
// Remove the lock file from the install script.
|
||||
if (hasDubLockFileNow != dubLockFile.isX) rm (dubLockFile);
|
||||
// Remove the backup copies if something failed.
|
||||
if (dub1 != 0 || dub2 != 0) {
|
||||
if (exists(dubCopyFile)) std.file.remove(dubCopyFile);
|
||||
if (exists(dubLockCopyFile)) std.file.remove(dubLockCopyFile);
|
||||
if (dub1 || dub2) {
|
||||
restore(dubFile, true);
|
||||
restore(dubLockFile, true);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Replace the dub file content if needed.
|
||||
if (isFirstRun) {
|
||||
std.file.write(dubFile, dubFileContent);
|
||||
if (exists(dubLockFile)) std.file.remove(dubLockFile);
|
||||
// Remove the backup copies.
|
||||
if (exists(dubCopyFile)) std.file.remove(dubCopyFile);
|
||||
if (exists(dubLockCopyFile)) std.file.remove(dubLockCopyFile);
|
||||
} else {
|
||||
// Replace the "dirty" files with the backup copies.
|
||||
// NOTE: raylib-d will change the content of the dub file and this is considered dirty.
|
||||
if (exists(dubCopyFile)) {
|
||||
std.file.write(dubFile, std.file.readText(dubCopyFile));
|
||||
std.file.remove(dubCopyFile);
|
||||
}
|
||||
if (exists(dubLockCopyFile)) {
|
||||
std.file.write(dubLockFile, std.file.readText(dubLockCopyFile));
|
||||
std.file.remove(dubLockCopyFile);
|
||||
}
|
||||
}
|
||||
// Clean stuff.
|
||||
if (isFirstRun) paste(dubFile, dubFileContent);
|
||||
restore(dubFile);
|
||||
restore(dubLockFile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(string[] args) {
|
||||
auto result = 0;
|
||||
auto isFirstRun = !exists(assetsDir);
|
||||
auto isSimpProject = !exists(dubFile);
|
||||
auto isFirstRun = !assetsDir.isX;
|
||||
auto isSimpProject = !dubFile.isX;
|
||||
if (isSimpProject) {
|
||||
result = runSimpSetup(args[1 .. $], isFirstRun);
|
||||
} else {
|
||||
result = runDubSetup(args[1 .. $], isFirstRun);
|
||||
}
|
||||
if (result == 0) writeln("Done!");
|
||||
if (result == 0) echo("Done!");
|
||||
return result;
|
||||
}
|
||||
|
||||
// [Noby Library]
|
||||
|
||||
enum cloneExt = "._cl";
|
||||
|
||||
Level minLogLevel = Level.info;
|
||||
|
||||
alias Sz = size_t; /// The result of sizeof, ...
|
||||
alias Str = char[]; /// A string slice of chars.
|
||||
alias IStr = const(char)[]; /// A string slice of constant chars.
|
||||
|
||||
enum Level : ubyte {
|
||||
none,
|
||||
info,
|
||||
warning,
|
||||
error,
|
||||
}
|
||||
|
||||
bool isX(IStr path) {
|
||||
import std.file;
|
||||
return path.exists;
|
||||
}
|
||||
|
||||
bool isF(IStr path) {
|
||||
import std.file;
|
||||
return path.exists;
|
||||
}
|
||||
|
||||
bool isD(IStr path) {
|
||||
import std.file;
|
||||
return path.isDir;
|
||||
}
|
||||
|
||||
void echo(A...)(A args) {
|
||||
import std.stdio;
|
||||
writeln(args);
|
||||
}
|
||||
|
||||
void echon(A...)(A args) {
|
||||
import std.stdio;
|
||||
write(args);
|
||||
}
|
||||
|
||||
void cp(IStr source, IStr target) {
|
||||
import std.file;
|
||||
copy(source, target);
|
||||
}
|
||||
|
||||
void rm(IStr path) {
|
||||
import std.file;
|
||||
if (path.isX) remove(path);
|
||||
}
|
||||
|
||||
void mkdir(IStr path, bool isRecursive = false) {
|
||||
import std.file;
|
||||
if (!path.isX) {
|
||||
if (isRecursive) mkdirRecurse(path);
|
||||
else std.file.mkdir(path);
|
||||
}
|
||||
}
|
||||
|
||||
void rmdir(IStr path, bool isRecursive = false) {
|
||||
import std.file;
|
||||
if (!path.isX) {
|
||||
if (isRecursive) rmdirRecurse(path);
|
||||
else std.file.rmdir(path);
|
||||
}
|
||||
}
|
||||
|
||||
IStr cat(IStr path) {
|
||||
import std.file;
|
||||
return path.isX ? readText(path) : "";
|
||||
}
|
||||
|
||||
IStr[] ls(IStr path = ".", bool isRecursive = false) {
|
||||
import std.file;
|
||||
IStr[] result;
|
||||
foreach (dir; dirEntries(cast(string) path, isRecursive ? SpanMode.breadth : SpanMode.shallow)) {
|
||||
result ~= dir.name;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
IStr basename(IStr path) {
|
||||
import std.path;
|
||||
return baseName(path);
|
||||
}
|
||||
|
||||
IStr realpath(IStr path) {
|
||||
import std.path;
|
||||
return absolutePath(cast(string) path);
|
||||
}
|
||||
|
||||
IStr read() {
|
||||
import std.stdio;
|
||||
import std.string;
|
||||
return readln().strip();
|
||||
}
|
||||
|
||||
IStr readYesNo(IStr text, IStr firstValue = "?") {
|
||||
auto result = firstValue;
|
||||
while (true) {
|
||||
if (result.length == 0) result = "Y";
|
||||
if (result.isYesOrNo) break;
|
||||
echon(text, " [Y/n] ");
|
||||
result = read();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
IStr join(IStr[] args...) {
|
||||
import std.path;
|
||||
return buildPath(args);
|
||||
}
|
||||
|
||||
bool isYes(IStr arg) {
|
||||
return (arg.length == 1 && (arg[0] == 'Y' || arg[0] == 'y'));
|
||||
}
|
||||
|
||||
bool isNo(IStr arg) {
|
||||
return (arg.length == 1 && (arg[0] == 'N' || arg[0] == 'n'));
|
||||
}
|
||||
|
||||
bool isYesOrNo(IStr arg) {
|
||||
return arg.isYes || arg.isNo;
|
||||
}
|
||||
|
||||
bool startsWith(IStr str, IStr start) {
|
||||
if (str.length < start.length) return false;
|
||||
return str[0 .. start.length] == start;
|
||||
}
|
||||
|
||||
bool endsWith(IStr str, IStr end) {
|
||||
if (str.length < end.length) return false;
|
||||
return str[$ - end.length .. $] == end;
|
||||
}
|
||||
|
||||
void paste(IStr path, IStr content, bool isOnlyMaking = false) {
|
||||
import std.file;
|
||||
if (isOnlyMaking) {
|
||||
if (!path.isX) write(path, content);
|
||||
} else {
|
||||
write(path, content);
|
||||
}
|
||||
}
|
||||
|
||||
void clone(IStr path) {
|
||||
if (path.isX) paste(path ~ cloneExt, cat(path));
|
||||
}
|
||||
|
||||
void restore(IStr path, bool isOnlyRemoving = false) {
|
||||
auto clonePath = path ~ cloneExt;
|
||||
if (clonePath.isX) {
|
||||
if (!isOnlyRemoving) paste(path, cat(clonePath));
|
||||
rm(clonePath);
|
||||
}
|
||||
}
|
||||
|
||||
void log(Level level, IStr text) {
|
||||
if (minLogLevel == 0 || minLogLevel > level) return;
|
||||
with (Level) final switch (level) {
|
||||
case info: echo("[INFO] ", text); break;
|
||||
case warning: echo("[WARNING] ", text); break;
|
||||
case error: echo("[ERROR] ", text); break;
|
||||
case none: break;
|
||||
}
|
||||
}
|
||||
|
||||
void logf(A...)(Level level, IStr text, A args) {
|
||||
import std.format;
|
||||
log(level, text.format(args));
|
||||
}
|
||||
|
||||
int cmd(IStr[] args...) {
|
||||
import std.stdio;
|
||||
import std.process;
|
||||
writeln("[CMD] ", args);
|
||||
try {
|
||||
return spawnProcess(args).wait();
|
||||
} catch (Exception e) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue