create-proyect-cli 1.2.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitignore +2 -0
- package/README.md +58 -24
- package/binary-install.js +212 -0
- package/binary.js +128 -0
- package/install.js +4 -0
- package/npm-shrinkwrap.json +545 -0
- package/package.json +101 -23
- package/run-create-proyect-cli.js +4 -0
- package/.idea/misc.xml +0 -6
- package/.idea/modules.xml +0 -8
- package/.idea/proyecto-cli.iml +0 -9
- package/.idea/vcs.xml +0 -6
- package/.idea/workspace.xml +0 -42
- package/.travis.yml +0 -12
- package/index.js +0 -192
package/.gitignore
ADDED
package/README.md
CHANGED
|
@@ -1,47 +1,81 @@
|
|
|
1
|
-
# Create Proyect CLI
|
|
1
|
+
# Create Proyect CLI 🚀
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/create-proyect-cli)
|
|
4
|
+
[](https://crates.io/crates/create-proyect-cli)
|
|
5
|
+
[](https://opensource.org/licenses/ISC)
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
Este CLI te permite realizar diversas acciones relacionadas con repositorios y proyectos, proporcionando una interfaz interactiva ultrarrápida para simplificar tareas comunes. Originalmente escrito en Node.js y ahora **reescrito en Rust para un rendimiento nativo y tiempos de inicio instantáneos**.
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
Con esta herramienta puedes clonar repositorios, inicializar proyectos en múltiples lenguajes y frameworks, configurar bases de datos, contenedores Docker y gestionar dependencias de manera fluida.
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
## 📦 Instalación
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
Gracias a su nuevo motor en Rust, puedes instalar este CLI desde el ecosistema que prefieras:
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
### Opción 1: Vía NPM (Recomendado para desarrolladores web)
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
Si ya utilizas el ecosistema de JavaScript/Node.js, instala el binario globalmente a través de npm:
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
```bash
|
|
20
|
+
npm install -g create-proyect-cli
|
|
21
|
+
```
|
|
18
22
|
|
|
19
|
-
|
|
23
|
+
### Opción 2: Vía Cargo (Para usuarios de Rust)
|
|
20
24
|
|
|
21
|
-
|
|
25
|
+
Si tienes Rust instalado en tu sistema, puedes compilar e instalar la herramienta directamente desde `crates.io`:
|
|
22
26
|
|
|
23
|
-
|
|
27
|
+
```bash
|
|
28
|
+
cargo install create-proyect-cli
|
|
29
|
+
```
|
|
24
30
|
|
|
25
|
-
|
|
31
|
+
## 💻 Uso
|
|
26
32
|
|
|
27
|
-
|
|
33
|
+
Una vez instalado, abre tu terminal en cualquier ubicación y ejecuta:
|
|
28
34
|
|
|
29
|
-
|
|
35
|
+
```bash
|
|
36
|
+
create-proyect-cli
|
|
37
|
+
```
|
|
30
38
|
|
|
31
|
-
|
|
39
|
+
El menú interactivo te guiará a través de las diferentes acciones disponibles, sin necesidad de recordar comandos o banderas complejas.
|
|
32
40
|
|
|
33
|
-
|
|
41
|
+
## 🛠️ Acciones Disponibles
|
|
34
42
|
|
|
35
|
-
|
|
43
|
+
### 1. Crear Proyecto (Generador Inteligente)
|
|
44
|
+
Genera la estructura base para nuevos proyectos. El CLI soporta múltiples ecosistemas y te guiará con configuraciones interactivas:
|
|
36
45
|
|
|
37
|
-
**
|
|
46
|
+
* **Frontend & Móvil:**
|
|
47
|
+
* Angular
|
|
48
|
+
* React
|
|
49
|
+
* Vue (Vite)
|
|
50
|
+
* Ionic
|
|
51
|
+
* **Backend Avanzado (API Express - TypeScript):**
|
|
52
|
+
* Generación de estructura escalable (rutas, controladores, middlewares).
|
|
53
|
+
* **Bases de datos:** Elección interactiva entre MySQL, MongoDB, SQL Server, MariaDB o SQLite.
|
|
54
|
+
* **ORMs:** Configuración automática de Prisma, TypeORM o Mongoose.
|
|
55
|
+
* **Documentación:** Instalación opcional de Swagger (`swagger-ui-express`).
|
|
56
|
+
* **Docker:** Generación automática de `Dockerfile` y `docker-compose.yml` vinculando tu API con la base de datos seleccionada.
|
|
57
|
+
* **Otros Lenguajes:**
|
|
58
|
+
* **Python:** Crea un proyecto base e inicializa automáticamente su entorno virtual (`venv`).
|
|
59
|
+
* **Rust:** Inicializa un proyecto nativo con Cargo.
|
|
38
60
|
|
|
39
|
-
|
|
61
|
+
### 2. Clonar Repositorio
|
|
62
|
+
Clona un repositorio Git proporcionando la URL y la ubicación destino, mostrando el progreso en tiempo real.
|
|
40
63
|
|
|
41
|
-
|
|
64
|
+
### 3. Instalar Dependencias
|
|
65
|
+
Navega automáticamente a la ubicación de tu proyecto y ejecuta la instalación de dependencias (`npm install`) en segundo plano.
|
|
42
66
|
|
|
43
|
-
|
|
67
|
+
### 4. Eliminar Repositorio Local
|
|
68
|
+
Borra de forma segura y recursiva un directorio o repositorio local especificando su ruta.
|
|
44
69
|
|
|
45
|
-
|
|
70
|
+
## 🤝 Contribuir
|
|
46
71
|
|
|
47
|
-
|
|
72
|
+
Si encuentras errores, tienes sugerencias de mejora o deseas agregar soporte para nuevos lenguajes, no dudes en crear un *issue* o enviar un *pull request* en el repositorio oficial.
|
|
73
|
+
|
|
74
|
+
**¡Gracias por usar este CLI! Esperamos que acelere la creación de todos tus proyectos.**
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## 📄 Licencia y Autoría
|
|
79
|
+
|
|
80
|
+
* **Autor:** Carlos Ignacio Olano Mares
|
|
81
|
+
* **Licencia:** GPL
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
const { createWriteStream, existsSync, mkdirSync, mkdtemp } = require("fs");
|
|
2
|
+
const { join, sep } = require("path");
|
|
3
|
+
const { spawnSync } = require("child_process");
|
|
4
|
+
const { tmpdir } = require("os");
|
|
5
|
+
|
|
6
|
+
const axios = require("axios");
|
|
7
|
+
const rimraf = require("rimraf");
|
|
8
|
+
const tmpDir = tmpdir();
|
|
9
|
+
|
|
10
|
+
const error = (msg) => {
|
|
11
|
+
console.error(msg);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
class Package {
|
|
16
|
+
constructor(platform, name, url, filename, zipExt, binaries) {
|
|
17
|
+
let errors = [];
|
|
18
|
+
if (typeof url !== "string") {
|
|
19
|
+
errors.push("url must be a string");
|
|
20
|
+
} else {
|
|
21
|
+
try {
|
|
22
|
+
new URL(url);
|
|
23
|
+
} catch (e) {
|
|
24
|
+
errors.push(e);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (name && typeof name !== "string") {
|
|
28
|
+
errors.push("package name must be a string");
|
|
29
|
+
}
|
|
30
|
+
if (!name) {
|
|
31
|
+
errors.push("You must specify the name of your package");
|
|
32
|
+
}
|
|
33
|
+
if (binaries && typeof binaries !== "object") {
|
|
34
|
+
errors.push("binaries must be a string => string map");
|
|
35
|
+
}
|
|
36
|
+
if (!binaries) {
|
|
37
|
+
errors.push("You must specify the binaries in the package");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (errors.length > 0) {
|
|
41
|
+
let errorMsg =
|
|
42
|
+
"One or more of the parameters you passed to the Binary constructor are invalid:\n";
|
|
43
|
+
errors.forEach((error) => {
|
|
44
|
+
errorMsg += error;
|
|
45
|
+
});
|
|
46
|
+
errorMsg +=
|
|
47
|
+
'\n\nCorrect usage: new Package("my-binary", "https://example.com/binary/download.tar.gz", {"my-binary": "my-binary"})';
|
|
48
|
+
error(errorMsg);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
this.platform = platform;
|
|
52
|
+
this.url = url;
|
|
53
|
+
this.name = name;
|
|
54
|
+
this.filename = filename;
|
|
55
|
+
this.zipExt = zipExt;
|
|
56
|
+
this.installDirectory = join(__dirname, "node_modules", ".bin_real");
|
|
57
|
+
this.binaries = binaries;
|
|
58
|
+
|
|
59
|
+
if (!existsSync(this.installDirectory)) {
|
|
60
|
+
mkdirSync(this.installDirectory, { recursive: true });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
exists() {
|
|
65
|
+
for (const binaryName in this.binaries) {
|
|
66
|
+
const binRelPath = this.binaries[binaryName];
|
|
67
|
+
const binPath = join(this.installDirectory, binRelPath);
|
|
68
|
+
if (!existsSync(binPath)) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
install(fetchOptions, suppressLogs = false) {
|
|
76
|
+
if (this.exists()) {
|
|
77
|
+
if (!suppressLogs) {
|
|
78
|
+
console.error(
|
|
79
|
+
`${this.name} is already installed, skipping installation.`,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
return Promise.resolve();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (existsSync(this.installDirectory)) {
|
|
86
|
+
rimraf.sync(this.installDirectory);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
mkdirSync(this.installDirectory, { recursive: true });
|
|
90
|
+
|
|
91
|
+
if (!suppressLogs) {
|
|
92
|
+
console.error(`Downloading release from ${this.url}`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return axios({ ...fetchOptions, url: this.url, responseType: "stream" })
|
|
96
|
+
.then((res) => {
|
|
97
|
+
return new Promise((resolve, reject) => {
|
|
98
|
+
mkdtemp(`${tmpDir}${sep}`, (err, directory) => {
|
|
99
|
+
let tempFile = join(directory, this.filename);
|
|
100
|
+
const sink = res.data.pipe(createWriteStream(tempFile));
|
|
101
|
+
sink.on("error", (err) => reject(err));
|
|
102
|
+
sink.on("close", () => {
|
|
103
|
+
if (/\.tar\.*/.test(this.zipExt)) {
|
|
104
|
+
const result = spawnSync("tar", [
|
|
105
|
+
"xf",
|
|
106
|
+
tempFile,
|
|
107
|
+
// The tarballs are stored with a leading directory
|
|
108
|
+
// component; we strip one component in the
|
|
109
|
+
// shell installers too.
|
|
110
|
+
"--strip-components",
|
|
111
|
+
"1",
|
|
112
|
+
"-C",
|
|
113
|
+
this.installDirectory,
|
|
114
|
+
]);
|
|
115
|
+
if (result.status == 0) {
|
|
116
|
+
resolve();
|
|
117
|
+
} else if (result.error) {
|
|
118
|
+
reject(result.error);
|
|
119
|
+
} else {
|
|
120
|
+
reject(
|
|
121
|
+
new Error(
|
|
122
|
+
`An error occurred untarring the artifact: stdout: ${result.stdout}; stderr: ${result.stderr}`,
|
|
123
|
+
),
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
} else if (this.zipExt == ".zip") {
|
|
127
|
+
let result;
|
|
128
|
+
if (this.platform.artifactName.includes("windows")) {
|
|
129
|
+
// Windows does not have "unzip" by default on many installations, instead
|
|
130
|
+
// we use Expand-Archive from powershell
|
|
131
|
+
result = spawnSync("powershell.exe", [
|
|
132
|
+
"-NoProfile",
|
|
133
|
+
"-NonInteractive",
|
|
134
|
+
"-Command",
|
|
135
|
+
`& {
|
|
136
|
+
param([string]$LiteralPath, [string]$DestinationPath)
|
|
137
|
+
Expand-Archive -LiteralPath $LiteralPath -DestinationPath $DestinationPath -Force
|
|
138
|
+
}`,
|
|
139
|
+
tempFile,
|
|
140
|
+
this.installDirectory,
|
|
141
|
+
]);
|
|
142
|
+
} else {
|
|
143
|
+
result = spawnSync("unzip", [
|
|
144
|
+
"-q",
|
|
145
|
+
tempFile,
|
|
146
|
+
"-d",
|
|
147
|
+
this.installDirectory,
|
|
148
|
+
]);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (result.status == 0) {
|
|
152
|
+
resolve();
|
|
153
|
+
} else if (result.error) {
|
|
154
|
+
reject(result.error);
|
|
155
|
+
} else {
|
|
156
|
+
reject(
|
|
157
|
+
new Error(
|
|
158
|
+
`An error occurred unzipping the artifact: stdout: ${result.stdout}; stderr: ${result.stderr}`,
|
|
159
|
+
),
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
} else {
|
|
163
|
+
reject(
|
|
164
|
+
new Error(`Unrecognized file extension: ${this.zipExt}`),
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
})
|
|
171
|
+
.then(() => {
|
|
172
|
+
if (!suppressLogs) {
|
|
173
|
+
console.error(`${this.name} has been installed!`);
|
|
174
|
+
}
|
|
175
|
+
})
|
|
176
|
+
.catch((e) => {
|
|
177
|
+
error(`Error fetching release: ${e.message}`);
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
run(binaryName, fetchOptions) {
|
|
182
|
+
const promise = !this.exists()
|
|
183
|
+
? this.install(fetchOptions, true)
|
|
184
|
+
: Promise.resolve();
|
|
185
|
+
|
|
186
|
+
promise
|
|
187
|
+
.then(() => {
|
|
188
|
+
const [, , ...args] = process.argv;
|
|
189
|
+
|
|
190
|
+
const options = { cwd: process.cwd(), stdio: "inherit" };
|
|
191
|
+
|
|
192
|
+
const binRelPath = this.binaries[binaryName];
|
|
193
|
+
if (!binRelPath) {
|
|
194
|
+
error(`${binaryName} is not a known binary in ${this.name}`);
|
|
195
|
+
}
|
|
196
|
+
const binPath = join(this.installDirectory, binRelPath);
|
|
197
|
+
const result = spawnSync(binPath, args, options);
|
|
198
|
+
|
|
199
|
+
if (result.error) {
|
|
200
|
+
error(result.error);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
process.exit(result.status);
|
|
204
|
+
})
|
|
205
|
+
.catch((e) => {
|
|
206
|
+
error(e.message);
|
|
207
|
+
process.exit(1);
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
module.exports.Package = Package;
|
package/binary.js
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
const { Package } = require("./binary-install");
|
|
2
|
+
const os = require("os");
|
|
3
|
+
const cTable = require("console.table");
|
|
4
|
+
const libc = require("detect-libc");
|
|
5
|
+
const { configureProxy } = require("axios-proxy-builder");
|
|
6
|
+
|
|
7
|
+
const error = (msg) => {
|
|
8
|
+
console.error(msg);
|
|
9
|
+
process.exit(1);
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const {
|
|
13
|
+
name,
|
|
14
|
+
artifactDownloadUrls,
|
|
15
|
+
supportedPlatforms,
|
|
16
|
+
glibcMinimum,
|
|
17
|
+
} = require("./package.json");
|
|
18
|
+
|
|
19
|
+
// FIXME: implement NPM installer handling of fallback download URLs
|
|
20
|
+
const artifactDownloadUrl = artifactDownloadUrls[0];
|
|
21
|
+
const builderGlibcMajorVersion = glibcMinimum.major;
|
|
22
|
+
const builderGlibcMinorVersion = glibcMinimum.series;
|
|
23
|
+
|
|
24
|
+
const getPlatform = () => {
|
|
25
|
+
const rawOsType = os.type();
|
|
26
|
+
const rawArchitecture = os.arch();
|
|
27
|
+
|
|
28
|
+
// We want to use rust-style target triples as the canonical key
|
|
29
|
+
// for a platform, so translate the "os" library's concepts into rust ones
|
|
30
|
+
let osType = "";
|
|
31
|
+
switch (rawOsType) {
|
|
32
|
+
case "Windows_NT":
|
|
33
|
+
osType = "pc-windows-msvc";
|
|
34
|
+
break;
|
|
35
|
+
case "Darwin":
|
|
36
|
+
osType = "apple-darwin";
|
|
37
|
+
break;
|
|
38
|
+
case "Linux":
|
|
39
|
+
osType = "unknown-linux-gnu";
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let arch = "";
|
|
44
|
+
switch (rawArchitecture) {
|
|
45
|
+
case "x64":
|
|
46
|
+
arch = "x86_64";
|
|
47
|
+
break;
|
|
48
|
+
case "arm64":
|
|
49
|
+
arch = "aarch64";
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (rawOsType === "Linux") {
|
|
54
|
+
if (libc.familySync() == "musl") {
|
|
55
|
+
osType = "unknown-linux-musl-dynamic";
|
|
56
|
+
} else if (libc.isNonGlibcLinuxSync()) {
|
|
57
|
+
console.warn(
|
|
58
|
+
"Your libc is neither glibc nor musl; trying static musl binary instead",
|
|
59
|
+
);
|
|
60
|
+
osType = "unknown-linux-musl-static";
|
|
61
|
+
} else {
|
|
62
|
+
let libcVersion = libc.versionSync();
|
|
63
|
+
let splitLibcVersion = libcVersion.split(".");
|
|
64
|
+
let libcMajorVersion = splitLibcVersion[0];
|
|
65
|
+
let libcMinorVersion = splitLibcVersion[1];
|
|
66
|
+
if (
|
|
67
|
+
libcMajorVersion != builderGlibcMajorVersion ||
|
|
68
|
+
libcMinorVersion < builderGlibcMinorVersion
|
|
69
|
+
) {
|
|
70
|
+
// We can't run the glibc binaries, but we can run the static musl ones
|
|
71
|
+
// if they exist
|
|
72
|
+
console.warn(
|
|
73
|
+
"Your glibc isn't compatible; trying static musl binary instead",
|
|
74
|
+
);
|
|
75
|
+
osType = "unknown-linux-musl-static";
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Assume the above succeeded and build a target triple to look things up with.
|
|
81
|
+
// If any of it failed, this lookup will fail and we'll handle it like normal.
|
|
82
|
+
let targetTriple = `${arch}-${osType}`;
|
|
83
|
+
let platform = supportedPlatforms[targetTriple];
|
|
84
|
+
|
|
85
|
+
if (!platform) {
|
|
86
|
+
error(
|
|
87
|
+
`Platform with type "${rawOsType}" and architecture "${rawArchitecture}" is not supported by ${name}.\nYour system must be one of the following:\n\n${Object.keys(
|
|
88
|
+
supportedPlatforms,
|
|
89
|
+
).join(",")}`,
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return platform;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const getPackage = () => {
|
|
97
|
+
const platform = getPlatform();
|
|
98
|
+
const url = `${artifactDownloadUrl}/${platform.artifactName}`;
|
|
99
|
+
let filename = platform.artifactName;
|
|
100
|
+
let ext = platform.zipExt;
|
|
101
|
+
let binary = new Package(platform, name, url, filename, ext, platform.bins);
|
|
102
|
+
|
|
103
|
+
return binary;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const install = (suppressLogs) => {
|
|
107
|
+
if (!artifactDownloadUrl || artifactDownloadUrl.length === 0) {
|
|
108
|
+
console.warn("in demo mode, not installing binaries");
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const package = getPackage();
|
|
112
|
+
const proxy = configureProxy(package.url);
|
|
113
|
+
|
|
114
|
+
return package.install(proxy, suppressLogs);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const run = (binaryName) => {
|
|
118
|
+
const package = getPackage();
|
|
119
|
+
const proxy = configureProxy(package.url);
|
|
120
|
+
|
|
121
|
+
package.run(binaryName, proxy);
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
module.exports = {
|
|
125
|
+
install,
|
|
126
|
+
run,
|
|
127
|
+
getPackage,
|
|
128
|
+
};
|
package/install.js
ADDED