feat: shift tauri create [not wired up] (#1330)
* Partial revert "refactor(tauri.js): remove create command (#1265)"
This reverts commit b29c0685bc
.
* shift templates/recipes over
* shift remaining files that weren't removed
* add change file
* rename to create-tauri-app
* adjust covector config
@ -169,6 +169,11 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"create-tauri-app": {
|
||||
"path": "./cli/create-tauri-app",
|
||||
"manager": "javascript",
|
||||
"dependencies": ["tauri.js"]
|
||||
},
|
||||
"tauri-utils": {
|
||||
"path": "./tauri-utils",
|
||||
"manager": "rust"
|
||||
|
6
.changes/revert-and-shift-tauri-create.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
"create-tauri-app": minor
|
||||
"tauri.js": patch
|
||||
---
|
||||
|
||||
Revert `tauri create` deletion and shift remaining pieces that weren't deleted to `create-tauri-app`.
|
209
cli/create-tauri-app/bin/create-tauri-app.js
Normal file
@ -0,0 +1,209 @@
|
||||
const parseArgs = require("minimist");
|
||||
const inquirer = require("inquirer");
|
||||
const { resolve } = require("path");
|
||||
const { merge } = require("lodash");
|
||||
const {
|
||||
recipeShortNames,
|
||||
recipeDescriptiveNames,
|
||||
recipeByDescriptiveName,
|
||||
recipeByShortName,
|
||||
} = require("../../tauri.js/dist/api/recipes");
|
||||
|
||||
/**
|
||||
* @type {object}
|
||||
* @property {boolean} h
|
||||
* @property {boolean} help
|
||||
* @property {string|boolean} f
|
||||
* @property {string|boolean} force
|
||||
* @property {boolean} l
|
||||
* @property {boolean} log
|
||||
* @property {boolean} d
|
||||
* @property {boolean} directory
|
||||
* @property {string} r
|
||||
* @property {string} recipe
|
||||
*/
|
||||
function main(cliArgs) {
|
||||
const argv = parseArgs(cliArgs, {
|
||||
alias: {
|
||||
h: "help",
|
||||
f: "force",
|
||||
l: "log",
|
||||
d: "directory",
|
||||
t: "tauri-path",
|
||||
A: "app-name",
|
||||
W: "window-title",
|
||||
D: "dist-dir",
|
||||
P: "dev-path",
|
||||
r: "recipe",
|
||||
},
|
||||
boolean: ["h", "l", "ci"],
|
||||
});
|
||||
|
||||
if (argv.help) {
|
||||
printUsage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (argv.ci) {
|
||||
runInit(argv);
|
||||
} else {
|
||||
getOptionsInteractive(argv).then((responses) => runInit(argv, responses));
|
||||
}
|
||||
}
|
||||
|
||||
function printUsage() {
|
||||
console.log(`
|
||||
Description
|
||||
Inits the Tauri template. If Tauri cannot find the tauri.conf.json
|
||||
it will create one.
|
||||
Usage
|
||||
$ tauri create
|
||||
Options
|
||||
--help, -h Displays this message
|
||||
--ci Skip prompts
|
||||
--force, -f Force init to overwrite [conf|template|all]
|
||||
--log, -l Logging [boolean]
|
||||
--directory, -d Set target directory for init
|
||||
--tauri-path, -t Path of the Tauri project to use (relative to the cwd)
|
||||
--app-name, -A Name of your Tauri application
|
||||
--window-title, -W Window title of your Tauri application
|
||||
--dist-dir, -D Web assets location, relative to <project-dir>/src-tauri
|
||||
--dev-path, -P Url of your dev server
|
||||
--recipe, -r Add UI framework recipe. None by default.
|
||||
Supported recipes: [${recipeShortNames.join("|")}]
|
||||
`);
|
||||
}
|
||||
|
||||
const getOptionsInteractive = (argv) => {
|
||||
let defaultAppName = argv.A;
|
||||
if (!defaultAppName) {
|
||||
try {
|
||||
const packageJson = JSON.parse(
|
||||
readFileSync(resolve(process.cwd(), "package.json")).toString()
|
||||
);
|
||||
defaultAppName = packageJson.displayName || packageJson.name;
|
||||
} catch {}
|
||||
}
|
||||
|
||||
return inquirer
|
||||
.prompt([
|
||||
{
|
||||
type: "input",
|
||||
name: "appName",
|
||||
message: "What is your app name?",
|
||||
default: defaultAppName,
|
||||
when: !argv.A,
|
||||
},
|
||||
{
|
||||
type: "input",
|
||||
name: "tauri.window.title",
|
||||
message: "What should the window title be?",
|
||||
default: "Tauri App",
|
||||
when: () => !argv.W,
|
||||
},
|
||||
{
|
||||
type: "list",
|
||||
name: "recipeName",
|
||||
message: "Would you like to add a UI recipe?",
|
||||
choices: recipeDescriptiveNames,
|
||||
default: "No recipe",
|
||||
when: () => !argv.r,
|
||||
},
|
||||
])
|
||||
.then((answers) =>
|
||||
inquirer
|
||||
.prompt([
|
||||
{
|
||||
type: "input",
|
||||
name: "build.devPath",
|
||||
message: "What is the url of your dev server?",
|
||||
default: "http://localhost:4000",
|
||||
when: () =>
|
||||
(!argv.P && !argv.p && answers.recipeName === "No recipe") ||
|
||||
argv.r === "none",
|
||||
},
|
||||
{
|
||||
type: "input",
|
||||
name: "build.distDir",
|
||||
message:
|
||||
'Where are your web assets (HTML/CSS/JS) located, relative to the "<current dir>/src-tauri" folder that will be created?',
|
||||
default: "../dist",
|
||||
when: () =>
|
||||
(!argv.D && answers.recipeName === "No recipe") ||
|
||||
argv.r === "none",
|
||||
},
|
||||
])
|
||||
.then((answers2) => ({ ...answers, ...answers2 }))
|
||||
)
|
||||
.catch((error) => {
|
||||
if (error.isTtyError) {
|
||||
// Prompt couldn't be rendered in the current environment
|
||||
console.log(
|
||||
"It appears your terminal does not support interactive prompts. Using default values."
|
||||
);
|
||||
runInit();
|
||||
} else {
|
||||
// Something else when wrong
|
||||
console.error("An unknown error occurred:", error);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
async function runInit(argv, config = {}) {
|
||||
const { appName, recipeName, ...configOptions } = config;
|
||||
const init = require("../../tauri.js/dist/api/init");
|
||||
|
||||
let recipe;
|
||||
let recipeSelection = "none";
|
||||
|
||||
if (recipeName !== undefined) {
|
||||
recipe = recipeByDescriptiveName(recipeName);
|
||||
} else if (argv.r) {
|
||||
recipe = recipeByShortName(argv.r);
|
||||
}
|
||||
|
||||
let buildConfig = {
|
||||
distDir: argv.D,
|
||||
devPath: argv.P,
|
||||
};
|
||||
|
||||
if (recipe !== undefined) {
|
||||
recipeSelection = recipe.shortName;
|
||||
buildConfig = recipe.configUpdate(buildConfig);
|
||||
}
|
||||
|
||||
const directory = argv.d || process.cwd();
|
||||
|
||||
init({
|
||||
directory,
|
||||
force: argv.f || null,
|
||||
logging: argv.l || null,
|
||||
tauriPath: argv.t || null,
|
||||
appName: appName || argv.A || null,
|
||||
customConfig: merge(configOptions, {
|
||||
build: buildConfig,
|
||||
tauri: {
|
||||
window: {
|
||||
title: argv.W,
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
const {
|
||||
installDependencies,
|
||||
} = require("../../tauri.js/dist/api/dependency-manager");
|
||||
await installDependencies();
|
||||
|
||||
if (recipe !== undefined) {
|
||||
const {
|
||||
installRecipeDependencies,
|
||||
runRecipePostConfig,
|
||||
} = require("../../tauri.js/dist/api/recipes/install");
|
||||
|
||||
await installRecipeDependencies(recipe, directory);
|
||||
await runRecipePostConfig(recipe, directory);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = main;
|
22
cli/create-tauri-app/package.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "create-tauri-app",
|
||||
"version": "0.0.0",
|
||||
"description": "Create Tauri App in seconds",
|
||||
"bin": {
|
||||
"create-tauri-app": "./bin/create-tauri-app.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/tauri-apps/tauri.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/tauri-apps/tauri/issues"
|
||||
},
|
||||
"homepage": "https://github.com/tauri-apps/tauri#readme",
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.5",
|
||||
"scaffe": "^0.1.5",
|
||||
"tauri": "^0.14.0"
|
||||
}
|
||||
}
|
@ -1,99 +1,99 @@
|
||||
import { ManagementType, Result } from './types'
|
||||
import { ManagementType, Result } from "./types";
|
||||
import {
|
||||
getNpmLatestVersion,
|
||||
getNpmPackageVersion,
|
||||
installNpmPackage,
|
||||
installNpmDevPackage,
|
||||
updateNpmPackage,
|
||||
semverLt
|
||||
} from './util'
|
||||
import logger from '../../helpers/logger'
|
||||
import { resolve } from '../../helpers/app-paths'
|
||||
import inquirer from 'inquirer'
|
||||
import { existsSync } from 'fs'
|
||||
import { sync as crossSpawnSync } from 'cross-spawn'
|
||||
semverLt,
|
||||
} from "./util";
|
||||
import logger from "../../../tauri.js/src/helpers/logger";
|
||||
import { resolve } from "../../../tauri.js/src/helpers/app-paths";
|
||||
import inquirer from "inquirer";
|
||||
import { existsSync } from "fs";
|
||||
import { sync as crossSpawnSync } from "cross-spawn";
|
||||
|
||||
const log = logger('dependency:npm-packages')
|
||||
const log = logger("dependency:npm-packages");
|
||||
|
||||
async function manageDependencies(
|
||||
managementType: ManagementType,
|
||||
dependencies: string[]
|
||||
): Promise<Result> {
|
||||
const installedDeps = []
|
||||
const updatedDeps = []
|
||||
const installedDeps = [];
|
||||
const updatedDeps = [];
|
||||
|
||||
const npmChild = crossSpawnSync('npm', ['--version'])
|
||||
const yarnChild = crossSpawnSync('yarn', ['--version'])
|
||||
const npmChild = crossSpawnSync("npm", ["--version"]);
|
||||
const yarnChild = crossSpawnSync("yarn", ["--version"]);
|
||||
if (
|
||||
(npmChild.status ?? npmChild.error) &&
|
||||
(yarnChild.status ?? yarnChild.error)
|
||||
) {
|
||||
throw new Error(
|
||||
'must have `npm` or `yarn` installed to manage dependenices'
|
||||
)
|
||||
"must have `npm` or `yarn` installed to manage dependenices"
|
||||
);
|
||||
}
|
||||
|
||||
if (existsSync(resolve.app('package.json'))) {
|
||||
if (existsSync(resolve.app("package.json"))) {
|
||||
for (const dependency of dependencies) {
|
||||
const currentVersion = await getNpmPackageVersion(dependency)
|
||||
const currentVersion = await getNpmPackageVersion(dependency);
|
||||
if (currentVersion === null) {
|
||||
log(`Installing ${dependency}...`)
|
||||
log(`Installing ${dependency}...`);
|
||||
if (managementType === ManagementType.Install) {
|
||||
await installNpmPackage(dependency)
|
||||
await installNpmPackage(dependency);
|
||||
} else if (managementType === ManagementType.InstallDev) {
|
||||
await installNpmDevPackage(dependency)
|
||||
await installNpmDevPackage(dependency);
|
||||
}
|
||||
installedDeps.push(dependency)
|
||||
installedDeps.push(dependency);
|
||||
} else if (managementType === ManagementType.Update) {
|
||||
const latestVersion = await getNpmLatestVersion(dependency)
|
||||
const latestVersion = await getNpmLatestVersion(dependency);
|
||||
if (semverLt(currentVersion, latestVersion)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-member-access
|
||||
const inquired = await inquirer.prompt([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'answer',
|
||||
type: "confirm",
|
||||
name: "answer",
|
||||
message: `[NPM]: "${dependency}" latest version is ${latestVersion}. Do you want to update?`,
|
||||
default: false
|
||||
}
|
||||
])
|
||||
default: false,
|
||||
},
|
||||
]);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-member-access
|
||||
if (inquired.answer) {
|
||||
log(`Updating ${dependency}...`)
|
||||
updateNpmPackage(dependency)
|
||||
updatedDeps.push(dependency)
|
||||
log(`Updating ${dependency}...`);
|
||||
updateNpmPackage(dependency);
|
||||
updatedDeps.push(dependency);
|
||||
}
|
||||
} else {
|
||||
log(`"${dependency}" is up to date`)
|
||||
log(`"${dependency}" is up to date`);
|
||||
}
|
||||
} else {
|
||||
log(`"${dependency}" is already installed`)
|
||||
log(`"${dependency}" is already installed`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const result: Result = new Map<ManagementType, string[]>()
|
||||
result.set(ManagementType.Install, installedDeps)
|
||||
result.set(ManagementType.Update, updatedDeps)
|
||||
const result: Result = new Map<ManagementType, string[]>();
|
||||
result.set(ManagementType.Install, installedDeps);
|
||||
result.set(ManagementType.Update, updatedDeps);
|
||||
|
||||
return result
|
||||
return result;
|
||||
}
|
||||
|
||||
const dependencies = ['tauri']
|
||||
const dependencies = ["tauri"];
|
||||
|
||||
async function install(): Promise<Result> {
|
||||
return await manageDependencies(ManagementType.Install, dependencies)
|
||||
return await manageDependencies(ManagementType.Install, dependencies);
|
||||
}
|
||||
|
||||
async function installThese(dependencies: string[]): Promise<Result> {
|
||||
return await manageDependencies(ManagementType.Install, dependencies)
|
||||
return await manageDependencies(ManagementType.Install, dependencies);
|
||||
}
|
||||
|
||||
async function installTheseDev(dependencies: string[]): Promise<Result> {
|
||||
return await manageDependencies(ManagementType.InstallDev, dependencies)
|
||||
return await manageDependencies(ManagementType.InstallDev, dependencies);
|
||||
}
|
||||
|
||||
async function update(): Promise<Result> {
|
||||
return await manageDependencies(ManagementType.Update, dependencies)
|
||||
return await manageDependencies(ManagementType.Update, dependencies);
|
||||
}
|
||||
|
||||
export { install, installThese, installTheseDev, update }
|
||||
export { install, installThese, installTheseDev, update };
|
44
cli/create-tauri-app/src/index.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { map, identity, find } from "lodash";
|
||||
import { TauriBuildConfig } from "./types/config";
|
||||
import { reactjs, reactts } from "./recipes/react";
|
||||
|
||||
export interface Recipe {
|
||||
descriptiveName: string;
|
||||
shortName: string;
|
||||
configUpdate: (cfg: TauriBuildConfig) => TauriBuildConfig;
|
||||
extraNpmDependencies: string[];
|
||||
extraNpmDevDependencies: string[];
|
||||
postConfiguration: (cwd: string) => void;
|
||||
}
|
||||
|
||||
const none = {
|
||||
descriptiveName: "No recipe",
|
||||
shortName: "none",
|
||||
configUpdate: identity,
|
||||
extraNpmDependencies: [],
|
||||
extraNpmDevDependencies: [],
|
||||
postConfiguration: (cwd: string) => {},
|
||||
};
|
||||
|
||||
export const allRecipes: Recipe[] = [none, reactjs, reactts];
|
||||
|
||||
export const recipeNames: Array<[string, string]> = map(
|
||||
allRecipes,
|
||||
(r: Recipe) => [r.shortName, r.descriptiveName]
|
||||
);
|
||||
|
||||
export const recipeByShortName = (name: string): Recipe | undefined =>
|
||||
find(allRecipes, (r: Recipe) => r.shortName === name);
|
||||
|
||||
export const recipeByDescriptiveName = (name: string): Recipe | undefined =>
|
||||
find(allRecipes, (r: Recipe) => r.descriptiveName === name);
|
||||
|
||||
export const recipeShortNames: string[] = map(
|
||||
allRecipes,
|
||||
(r: Recipe) => r.shortName
|
||||
);
|
||||
|
||||
export const recipeDescriptiveNames: string[] = map(
|
||||
allRecipes,
|
||||
(r: Recipe) => r.descriptiveName
|
||||
);
|
35
cli/create-tauri-app/src/install.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import {
|
||||
installThese,
|
||||
installTheseDev,
|
||||
} from "./dependency-manager/npm-packages";
|
||||
import { Recipe } from ".";
|
||||
import { Result } from "./dependency-manager/types";
|
||||
import logger from "../../tauri.js/src/helpers/logger";
|
||||
|
||||
export async function installRecipeDependencies(
|
||||
recipe: Recipe
|
||||
): Promise<Result> {
|
||||
const log = logger("recipe:install");
|
||||
|
||||
log(`Installing dependencies for ${recipe.descriptiveName}`);
|
||||
return await installThese(recipe.extraNpmDependencies).then(
|
||||
async (results) =>
|
||||
await installTheseDev(recipe.extraNpmDevDependencies).then(
|
||||
(results2) =>
|
||||
new Map([
|
||||
...Array.from(results.entries()),
|
||||
...Array.from(results2.entries()),
|
||||
])
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export async function runRecipePostConfig(
|
||||
recipe: Recipe,
|
||||
cwd: string
|
||||
): Promise<void> {
|
||||
const log = logger("recipe:postconfig");
|
||||
|
||||
log(`Running post configuration for ${recipe.descriptiveName}`);
|
||||
return await new Promise(() => recipe.postConfiguration(cwd));
|
||||
}
|
65
cli/create-tauri-app/src/recipes/react.ts
Normal file
@ -0,0 +1,65 @@
|
||||
import { Recipe } from ".";
|
||||
import { TauriBuildConfig } from "./../types/config";
|
||||
import { spawnSync } from "../../../tauri.js/src/helpers/spawn";
|
||||
import logger from "../../../tauri.js/src/helpers/logger";
|
||||
import copyTemplates from "../../../tauri.js/src/helpers/copy-templates";
|
||||
import { resolve, join } from "path";
|
||||
|
||||
const uiAppDir = "app-ui";
|
||||
|
||||
const log = logger("react-recipe");
|
||||
|
||||
const completeLogMsg = `
|
||||
Your installation completed.
|
||||
To start, run yarn tauri dev
|
||||
`;
|
||||
|
||||
const afterCra = (): void => {
|
||||
copyTemplates({
|
||||
source: resolve(__dirname, "../../templates/recipes/react/"),
|
||||
scope: {},
|
||||
target: join(uiAppDir, "./src/"),
|
||||
});
|
||||
log(completeLogMsg);
|
||||
};
|
||||
|
||||
const reactjs: Recipe = {
|
||||
descriptiveName: "React.js",
|
||||
shortName: "reactjs",
|
||||
configUpdate: (cfg: TauriBuildConfig): TauriBuildConfig => ({
|
||||
...cfg,
|
||||
distDir: `../${uiAppDir}/build`,
|
||||
devPath: "http://localhost:3000",
|
||||
beforeDevCommand: `yarn --cwd ${uiAppDir} start`,
|
||||
beforeBuildCommand: `yarn --cwd ${uiAppDir} build`,
|
||||
}),
|
||||
extraNpmDevDependencies: ["create-react-app"],
|
||||
extraNpmDependencies: ["react"],
|
||||
postConfiguration: (cwd: string) => {
|
||||
spawnSync("yarn", ["create-react-app", uiAppDir], cwd);
|
||||
afterCra();
|
||||
},
|
||||
};
|
||||
|
||||
const reactts: Recipe = {
|
||||
...reactjs,
|
||||
descriptiveName: "React with Typescript",
|
||||
shortName: "reactts",
|
||||
extraNpmDependencies: [
|
||||
"typescript",
|
||||
"@types/node",
|
||||
"@types/react",
|
||||
"@types/react-dom",
|
||||
"@types/jest",
|
||||
],
|
||||
postConfiguration: (cwd: string) => {
|
||||
spawnSync(
|
||||
"yarn",
|
||||
["create-react-app", "--template", "typescript", uiAppDir],
|
||||
cwd
|
||||
);
|
||||
afterCra();
|
||||
},
|
||||
};
|
||||
|
||||
export { reactjs, reactts };
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 9.6 KiB |
@ -1,128 +0,0 @@
|
||||
import https from 'https'
|
||||
import { IncomingMessage } from 'http'
|
||||
import { spawnSync } from '../../helpers/spawn'
|
||||
import { sync as crossSpawnSync } from 'cross-spawn'
|
||||
import { appDir, resolve as appResolve } from '../../helpers/app-paths'
|
||||
import { existsSync } from 'fs'
|
||||
import semver from 'semver'
|
||||
|
||||
const BASE_URL = 'https://docs.rs/crate/'
|
||||
|
||||
async function useYarn(): Promise<boolean> {
|
||||
const hasYarnLockfile = existsSync(appResolve.app('yarn.lock'))
|
||||
if (hasYarnLockfile) {
|
||||
return true
|
||||
} else {
|
||||
return await new Promise((resolve) => {
|
||||
const child = crossSpawnSync('npm', ['--version'])
|
||||
resolve(!!(child.status ?? child.error))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async function getCrateLatestVersion(crateName: string): Promise<string> {
|
||||
return await new Promise((resolve, reject) => {
|
||||
const url = `${BASE_URL}${crateName}`
|
||||
https.get(url, (res: IncomingMessage) => {
|
||||
if (res.statusCode !== 302 || !res.headers.location) {
|
||||
reject(res)
|
||||
} else {
|
||||
const version = res.headers.location.replace(url + '/', '')
|
||||
resolve(version)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async function getNpmLatestVersion(packageName: string): Promise<string> {
|
||||
if (await useYarn()) {
|
||||
const child = crossSpawnSync(
|
||||
'yarn',
|
||||
['info', packageName, 'versions', '--json'],
|
||||
{
|
||||
cwd: appDir
|
||||
}
|
||||
)
|
||||
const output = String(child.output[1])
|
||||
const packageJson = JSON.parse(output) as { data: string[] }
|
||||
return packageJson.data[packageJson.data.length - 1]
|
||||
} else {
|
||||
const child = crossSpawnSync('npm', ['show', packageName, 'version'], {
|
||||
cwd: appDir
|
||||
})
|
||||
return String(child.output[1]).replace('\n', '')
|
||||
}
|
||||
}
|
||||
|
||||
async function getNpmPackageVersion(
|
||||
packageName: string
|
||||
): Promise<string | null> {
|
||||
const child = (await useYarn())
|
||||
? crossSpawnSync(
|
||||
'yarn',
|
||||
['list', '--patern', packageName, '--depth', '0'],
|
||||
{
|
||||
cwd: appDir
|
||||
}
|
||||
)
|
||||
: crossSpawnSync('npm', ['list', packageName, 'version', '--depth', '0'], {
|
||||
cwd: appDir
|
||||
})
|
||||
const output = String(child.output[1])
|
||||
// eslint-disable-next-line security/detect-non-literal-regexp
|
||||
const matches = new RegExp(packageName + '@(\\S+)', 'g').exec(output)
|
||||
if (matches?.[1]) {
|
||||
return matches[1]
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
async function installNpmPackage(packageName: string): Promise<void> {
|
||||
if (await useYarn()) {
|
||||
spawnSync('yarn', ['add', packageName], appDir)
|
||||
} else {
|
||||
spawnSync('npm', ['install', packageName], appDir)
|
||||
}
|
||||
}
|
||||
|
||||
async function installNpmDevPackage(packageName: string): Promise<void> {
|
||||
if (await useYarn()) {
|
||||
spawnSync('yarn', ['add', packageName, '--dev'], appDir)
|
||||
} else {
|
||||
spawnSync('npm', ['install', packageName, '--save-dev'], appDir)
|
||||
}
|
||||
}
|
||||
|
||||
function updateNpmPackage(packageName: string): void {
|
||||
const usesYarn = existsSync(appResolve.app('yarn.lock'))
|
||||
if (usesYarn) {
|
||||
spawnSync('yarn', ['upgrade', packageName, '--latest'], appDir)
|
||||
} else {
|
||||
spawnSync('npm', ['install', `${packageName}@latest`], appDir)
|
||||
}
|
||||
}
|
||||
|
||||
function padVersion(version: string): string {
|
||||
let count = (version.match(/\./g) ?? []).length
|
||||
while (count < 2) {
|
||||
count++
|
||||
version += '.0'
|
||||
}
|
||||
return version
|
||||
}
|
||||
|
||||
function semverLt(first: string, second: string): boolean {
|
||||
return semver.lt(padVersion(first), padVersion(second))
|
||||
}
|
||||
|
||||
export {
|
||||
getCrateLatestVersion,
|
||||
getNpmLatestVersion,
|
||||
getNpmPackageVersion,
|
||||
installNpmPackage,
|
||||
installNpmDevPackage,
|
||||
updateNpmPackage,
|
||||
padVersion,
|
||||
semverLt
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
[package]
|
||||
name = "app"
|
||||
version = "0.1.0"
|
||||
description = "A Tauri App"
|
||||
authors = ["you"]
|
||||
license = ""
|
||||
repository = ""
|
||||
default-run = "app"
|
||||
edition = "2018"
|
||||
build = "src/build.rs"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
tauri = <%= tauriDep || `{ version = "0.5" }` %>
|
||||
|
||||
[target."cfg(windows)".build-dependencies]
|
||||
winres = "0.1"
|
||||
|
||||
[features]
|
||||
custom-protocol = [ "tauri/custom-protocol" ]
|
||||
|
||||
[[bin]]
|
||||
name = "app"
|
||||
path = "src/main.rs"
|
@ -1,10 +0,0 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
WixTools
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
config.json
|
||||
bundle.json
|
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 88 KiB |
@ -1,14 +0,0 @@
|
||||
max_width = 100
|
||||
hard_tabs = false
|
||||
tab_spaces = 2
|
||||
newline_style = "Auto"
|
||||
use_small_heuristics = "Default"
|
||||
reorder_imports = true
|
||||
reorder_modules = true
|
||||
remove_nested_parens = true
|
||||
edition = "2018"
|
||||
merge_derives = true
|
||||
use_try_shorthand = false
|
||||
use_field_init_shorthand = false
|
||||
force_explicit_abi = true
|
||||
imports_granularity = "Crate"
|
@ -1,16 +0,0 @@
|
||||
#[cfg(windows)]
|
||||
extern crate winres;
|
||||
|
||||
#[cfg(windows)]
|
||||
fn main() {
|
||||
if std::path::Path::new("icons/icon.ico").exists() {
|
||||
let mut res = winres::WindowsResource::new();
|
||||
res.set_icon_with_id("icons/icon.ico", "32512");
|
||||
res.compile().expect("Unable to find visual studio tools");
|
||||
} else {
|
||||
panic!("No Icon.ico found. Please add one or check the path");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn main() {}
|
@ -1,14 +0,0 @@
|
||||
#![cfg_attr(
|
||||
all(not(debug_assertions), target_os = "windows"),
|
||||
windows_subsystem = "windows"
|
||||
)]
|
||||
|
||||
#[derive(tauri::FromTauriContext)]
|
||||
struct Context;
|
||||
|
||||
fn main() {
|
||||
tauri::AppBuilder::<Context>::new()
|
||||
.build()
|
||||
.unwrap()
|
||||
.run();
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
use crate::tauri::process::{ProcessExt, Signal, SystemExt};
|
||||
|
||||
fn update() -> Result<(), String> {
|
||||
let target = tauri::platform::target_triple().map_err(|_| "Could not determine target")?;
|
||||
let github_release = tauri::updater::github::get_latest_release("jaemk", "self_update")
|
||||
.map_err(|_| "Could not fetch latest release")?;
|
||||
match github_release.asset_for(&target) {
|
||||
Some(github_release_asset) => {
|
||||
let release = tauri::updater::Release {
|
||||
version: github_release.tag.trim_start_matches('v').to_string(),
|
||||
download_url: github_release_asset.download_url,
|
||||
asset_name: github_release_asset.name,
|
||||
};
|
||||
|
||||
let status = tauri::updater::Update::configure()
|
||||
.unwrap()
|
||||
.release(release)
|
||||
.bin_path_in_archive("github")
|
||||
.bin_name("app")
|
||||
.bin_install_path(&tauri::command::command_path("app".to_string()).unwrap())
|
||||
.show_download_progress(true)
|
||||
.current_version(env!("CARGO_PKG_VERSION"))
|
||||
.build()
|
||||
.unwrap()
|
||||
.update()
|
||||
.unwrap();
|
||||
|
||||
println!("found release: {}", status.version());
|
||||
|
||||
/*let tmp_dir = tauri::dir::with_temp_dir(|dir| {
|
||||
let file_path = dir.path().join("my-temporary-note.pdf");
|
||||
let mut tmp_archive = std::fs::File::create(file_path).unwrap();
|
||||
tauri::http::download(&"https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf".to_string(), &mut tmp_archive, true).unwrap();
|
||||
});*/
|
||||
|
||||
Ok(())
|
||||
}
|
||||
None => Err(format!("Could not find release for target {}", target)),
|
||||
}
|
||||
}
|
||||
|
||||
fn restart_app(app_command: String) -> Result<(), String> {
|
||||
let mut system = tauri::process::System::new();
|
||||
let parent_process = tauri::process::get_parent_process(&mut system)
|
||||
.map_err(|_| "Could not determine parent process")?;
|
||||
if parent_process.name() == "app" {
|
||||
parent_process.kill(Signal::Kill);
|
||||
std::thread::sleep(std::time::Duration::from_secs(1));
|
||||
std::process::Command::new(app_command)
|
||||
.spawn()
|
||||
.map_err(|_| "Could not start app")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_updater() -> Result<(), String> {
|
||||
let app_command = tauri::command::relative_command("app".to_string())
|
||||
.map_err(|_| "Could not determine app path")?;
|
||||
update()?;
|
||||
restart_app(app_command)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
match run_updater() {
|
||||
Ok(_) => {}
|
||||
Err(err) => panic!(err),
|
||||
};
|
||||
}
|