From ed9bf4cc522918af03c4e22d86355897d2f58b85 Mon Sep 17 00:00:00 2001 From: Michael Vlasov Date: Wed, 24 Feb 2021 15:45:11 +0500 Subject: [PATCH 01/24] ADD: TONOS SE Controller --- CHANGELOG.md | 9 ++ package.json | 6 +- src/cli/index.ts | 114 +++++++++++--- src/controllers/index.ts | 3 +- src/controllers/se/commands.ts | 204 ++++++++++++++++++++++++ src/controllers/se/docker.ts | 266 ++++++++++++++++++++++++++++++++ src/controllers/se/index.ts | 24 +++ src/controllers/se/installer.ts | 173 +++++++++++++++++++++ src/core/utils.ts | 83 +++++++++- 9 files changed, 854 insertions(+), 28 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 src/controllers/se/commands.ts create mode 100644 src/controllers/se/docker.ts create mode 100644 src/controllers/se/index.ts create mode 100644 src/controllers/se/installer.ts diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..393eb42 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,9 @@ +# Release Notes + +All notable changes to this project will be documented in this file. + +## [0.2.0] - 2021-02-24 + +### Added + +- TONOS-SE Controller. diff --git a/package.json b/package.json index 8173ad7..a20cf62 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tondev", - "version": "0.1.7", + "version": "0.2.0", "description": "TON Dev Environment", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -35,7 +35,11 @@ "engines": { "node": ">=6" }, + "dependencies": { + "dockerode": "3.2.1" + }, "devDependencies": { + "@types/dockerode": "^3.2.2", "@types/node": "^12.12.6", "typescript": "^4.1.3" } diff --git a/src/cli/index.ts b/src/cli/index.ts index bfd2d33..0670754 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -1,13 +1,12 @@ -import {Command, CommandArg} from "../core"; -import {controllers} from "../controllers"; -import {consoleTerminal} from "../core/utils"; +import { Command, CommandArg, ToolController } from "../core"; +import { controllers } from "../controllers"; +import { consoleTerminal } from "../core/utils"; import * as fs from "fs"; import * as path from "path"; enum ParseState { OptionOrArg, OptionValue, - Arg, } type CommandLine = { @@ -22,44 +21,94 @@ function parseCommandLine(programArgs: string[]): CommandLine { const options: { [name: string]: any } = {}; for (const arg of programArgs) { - const argOption: string | null = arg.startsWith("-") - ? arg.substr(1) - : (arg.startsWith("--") ? arg.substr(2) : null); - - if (state === ParseState.OptionOrArg && argOption) { - option = argOption; - state = ParseState.OptionValue; - } else if (state === ParseState.OptionOrArg) { - args.push(arg); - state = ParseState.Arg; - } else if (state === ParseState.OptionValue) { - options[option] = arg; - state = ParseState.OptionOrArg; - } else if (state === ParseState.Arg) { - args.push(arg); + const argOption: string | null = + arg.startsWith("--") ? arg.substr(2) : (arg.startsWith("-") ? arg : null); + switch (state) { + case ParseState.OptionOrArg: + if (option !== "") { + options[option] = ""; + } + if (argOption) { + option = argOption; + state = ParseState.OptionValue; + } else { + option = ""; + args.push(arg); + } + break; + case ParseState.OptionValue: + options[option] = arg; + option = ""; + state = ParseState.OptionOrArg; + break; } } + if (option !== "") { + options[option] = ""; + } return { args, options, }; } -export function printUsage() { +export function printCommandUsage(controller: ToolController, command: Command) { + let usageArgs = ""; + const options: CommandArg[] = []; + const args: CommandArg[] = []; + for (const arg of command.args ?? []) { + if (arg.isArg) { + usageArgs += ` ${arg.name}`; + args.push(arg); + } else { + options.push(arg); + } + } + if (options.length > 0) { + usageArgs += ` [options]`; + } + console.log(`Use: tondev ${controller.name} ${command.name}${usageArgs}`); + if (args.length > 0) { + console.log("Args:"); + let colWidth = options.reduce((w, x) => Math.max(w, x.name.length), 0); + args.forEach(x => { + console.log(` ${x.name.padEnd(colWidth)} ${x.title ?? ""}`); + }); + } + console.log("Options:"); + console.log(` --help, -h Show command usage`); + let colWidth = options.reduce((w, x) => Math.max(w, x.name.length), 0); + options.forEach(x => { + console.log(` --${x.name.padEnd(colWidth)} ${x.title ?? ""}`); + }); + return; +} + +export function printUsage(useController?: ToolController, useCommand?: Command) { const pkg = JSON.parse(fs.readFileSync(path.resolve(__dirname, "..", "..", "package.json"), "utf8")); - console.log("Use: tondev command args..."); - console.log(`Version: ${pkg.version}`); + console.log(`TONDev Version: ${pkg.version}`); + if (useController && useCommand) { + printCommandUsage(useController, useCommand); + return; + } + console.log(`Use: tondev ${useController?.name ?? "tool"} ${useCommand?.name ?? "command"} args [options]`); + console.log(`Options:`); + console.log(` --help, -h Show command usage`); console.log("Commands:"); const commands: [string, Command][] = []; for (const controller of controllers) { for (const command of controller.commands) { - commands.push([`${controller.name} ${command.name}`, command]) + if ((useController === undefined || useController === controller) + && (useCommand === undefined || useCommand === command)) { + commands.push([`${controller.name} ${command.name}`, command]) + } } } let colWidth = commands.reduce((w, x) => Math.max(w, x[0].length), 0); commands.forEach(x => { - console.log(` ${x[0].padEnd(colWidth)} ${x[1].title}`); + console.log(` ${x[0].padEnd(colWidth)} ${x[1].title ?? ""}`); }); + return; } function missingArgError(arg: CommandArg): Error { @@ -91,6 +140,13 @@ function extractNextArg(commandLine: CommandLine): string { return (commandLine.args.splice(0, 1)[0] ?? "").toLowerCase(); } +function getOption(commandLine: CommandLine, name: string, alias: string): string | undefined { + if (commandLine.options[name] !== undefined) { + return commandLine.options[name]; + } + return commandLine.options[alias]; +} + export async function run() { const commandLine = parseCommandLine(process.argv.slice(2)); if (commandLine.args.length === 0) { @@ -105,7 +161,15 @@ export async function run() { const commandName = extractNextArg(commandLine); const command = controller.commands.find(x => x.name === commandName); if (!command) { - throw new Error(`Unknown command: ${commandName}`); + if (commandName) { + throw new Error(`Unknown command: ${commandName}`); + } + printUsage(controller, command); + return; + } + if (getOption(commandLine, "help", "-h") !== undefined) { + printUsage(controller, command); + return; } const args: { [name: string]: any } = {}; for (const arg of command.args ?? []) { diff --git a/src/controllers/index.ts b/src/controllers/index.ts index 5cce1f0..3fda0da 100644 --- a/src/controllers/index.ts +++ b/src/controllers/index.ts @@ -1,7 +1,8 @@ import {Solidity} from "./solidity"; // import {TestSuite} from "./ts"; import {JsApps} from "./js"; +import { SE } from "./se"; export const controllers = [ - Solidity, JsApps, + Solidity, JsApps, SE, ]; diff --git a/src/controllers/se/commands.ts b/src/controllers/se/commands.ts new file mode 100644 index 0000000..d455740 --- /dev/null +++ b/src/controllers/se/commands.ts @@ -0,0 +1,204 @@ +import { + filterInstances, + getConfig, + getInstanceInfo, + getLatestVersion, + getVersions, + instanceContainerDef, + isInstanceMatched, + setConfig +} from "./installer"; +import { Command, CommandArg, Terminal } from "../../core"; +import { ContainerDef, ContainerStatus, DevDocker } from "./docker"; + +export const instanceArg: CommandArg = { + name: "instance", + type: "string", + defaultValue: "*", + title: "SE Instance Filter", +}; + +async function controlInstances( + instanceFilter: string, + control: (docker: DevDocker, defs: ContainerDef[]) => Promise +): Promise { + const defs: ContainerDef[] = (await filterInstances(instanceFilter)).map(instanceContainerDef); + await control(new DevDocker(), defs); +} + + +export const seInfoCommand: Command = { + name: "info", + title: "Show TON SE Info", + args: [instanceArg], + async run(terminal: Terminal, args: { instance: string }): Promise { + const docker = new DevDocker(); + for (const instance of await filterInstances(args.instance)) { + const info = await getInstanceInfo(docker, instance); + terminal.log(`${instance.name}: ${info.state}`); + terminal.log(` Config: --version ${instance.version} --port ${instance.port} --db-port ${instance.dbPort ?? "none"}`); + terminal.log(` Docker: ${info.docker.container} (${info.docker.image})`); + } + }, +}; + +export const seVersionCommand: Command = { + name: "version", + title: "Show Node SE Version", + args: [{ + name: "available", + type: "string", + defaultValue: "false", + title: "Show available versions", + }], + async run(terminal: Terminal, args: { available: string }): Promise { + for (const instance of (await getConfig()).instances) { + terminal.log(`${instance.name}: ${instance.version}`); + } + if (args.available === "true") { + terminal.log(`Available: ${(await getVersions()).join(", ")}`); + } + }, +}; + +export const seStartCommand: Command = { + name: "start", + title: "Start SE Instance", + args: [instanceArg], + async run(terminal: Terminal, args: { instance: string }): Promise { + await controlInstances(args.instance, async (docker, defs) => { + await docker.startupContainers(terminal, defs, ContainerStatus.running); + }); + }, +}; + +export const seStopCommand: Command = { + name: "stop", + title: "Stop SE Instance", + args: [instanceArg], + async run(terminal: Terminal, args: { instance: string }): Promise { + await controlInstances(args.instance, async (docker, defs) => { + await docker.shutdownContainers(terminal, defs, ContainerStatus.created); + }); + }, +}; + +export const seResetCommand: Command = { + name: "reset", + title: "Reset SE Instance", + args: [instanceArg], + async run(terminal: Terminal, args: { instance: string }): Promise { + await controlInstances(args.instance, async (docker, defs) => { + await docker.shutdownContainers(terminal, defs, ContainerStatus.missing); + await docker.startupContainers(terminal, defs, ContainerStatus.running); + }); + }, +}; + +export const seUpdateCommand: Command = { + name: "update", + title: "Update SE Instance Version", + args: [instanceArg], + async run(terminal: Terminal, args: { instance: string }): Promise { + const config = await getConfig(); + const latestVersion = await getLatestVersion(); + const docker = new DevDocker(); + for (const instance of config.instances) { + if (isInstanceMatched(instance, args.instance)) { + instance.version = latestVersion; + const def = instanceContainerDef(instance); + await docker.shutdownContainer(terminal, def, ContainerStatus.missing); + await docker.startupContainer(terminal, def, ContainerStatus.created); + } + } + setConfig(config); + }, +}; + +export const seSetCommand: Command = { + name: "set", + title: "Update SE Instance Config", + args: [instanceArg, + { + name: "version", + title: "SE version (version number or `latest`)", + type: "string", + defaultValue: "", + + }, + { + name: "port", + title: "Port on localhost used to expose GraphQL API", + type: "string", + defaultValue: "", + + }, + { + name: "db-port", + title: "Port on localhost used to expose ArangoDB API (number or `none`)", + type: "string", + defaultValue: "", + } + ], + async run(terminal: Terminal, args: { + version: string, + port: string, + "db-port": string, + instance: string + }): Promise { + const config = await getConfig(); + const docker = new DevDocker(); + + let version: string | undefined = undefined; + if (args.version !== "") { + if (args.version.toLowerCase() === "latest") { + version = await getLatestVersion(); + } else { + if (!(await getVersions()).includes(args.version)) { + throw new Error(`Invalid version: ${args.version}`); + } + version = args.version; + } + } + + let port: number | undefined = undefined; + if (args.port !== "") { + port = Number.parseInt(args.port); + if (port === undefined) { + throw new Error(`Invalid port: ${args.port}`); + } + } + + let dbPort: number | "none" | undefined = undefined; + if (args["db-port"] !== "") { + if (args["db-port"].toLowerCase() === "none") { + dbPort = "none"; + } else { + dbPort = Number.parseInt(args["db-port"]); + if (port === undefined) { + throw new Error(`Invalid db-port: ${args["db-port"]}`); + } + } + } + + for (const instance of config.instances) { + if (isInstanceMatched(instance, args.instance)) { + if (version !== undefined) { + instance.version = version; + } + if (port !== undefined) { + instance.port = port; + } + if (dbPort === "none") { + delete instance.dbPort; + } else if (dbPort !== undefined) { + instance.dbPort = dbPort; + } + const def = instanceContainerDef(instance); + await docker.shutdownContainer(terminal, def, ContainerStatus.missing); + await docker.startupContainer(terminal, def, ContainerStatus.created); + } + } + setConfig(config); + }, +}; \ No newline at end of file diff --git a/src/controllers/se/docker.ts b/src/controllers/se/docker.ts new file mode 100644 index 0000000..40f60d4 --- /dev/null +++ b/src/controllers/se/docker.ts @@ -0,0 +1,266 @@ +/* + * Copyright 2018-2020 TON DEV SOLUTIONS LTD. + * + * Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of the + * License at: https://www.ton.dev/licenses + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific TON DEV software governing permissions and + * limitations under the License. + * + */ +import Dockerode, { Container, ContainerInfo, DockerVersion, Image, ImageInfo } from "dockerode"; +import Docker from "dockerode"; +import { Terminal } from "../../core"; + +import { progress, progressDone, progressLine, versionToNumber } from "../../core/utils"; + + +export enum ContainerStatus { + missing = 0, + created = 1, + running = 2, +}; + +export interface ContainerDef { + requiredImage: string, + containerName: string, + + createContainer(docker: DevDocker): Promise +} + + +class DevDocker { + client: Dockerode; + _images: ImageInfo[] | null; + _containers: ContainerInfo[] | null; + _onStartupImagesPassed: boolean; + onStartupImages: ((images: ImageInfo[]) => void) | null; + onBeforePull: ((repoTag: string) => Promise) | null; + + constructor() { + this.client = new Docker(); + this.onStartupImages = null; + this.onBeforePull = null; + this._onStartupImagesPassed = false; + this._images = null; + this._containers = null; + } + + dropCache() { + this._images = null; + this._containers = null; + } + + async getImageInfos(): Promise { + if (!this._images) { + const images = await this.client.listImages({ all: true }); + this._images = images; + if (!this._onStartupImagesPassed) { + this._onStartupImagesPassed = true; + if (this.onStartupImages) { + this.onStartupImages(images); + } + } + this._images = images; + } + return this._images || []; + } + + async getContainerInfos(): Promise { + if (!this._containers) { + this._containers = await this.client.listContainers({ all: true }); + } + return this._containers || []; + } + + async numericVersion(): Promise { + const version: DockerVersion = await this.client.version(); + return versionToNumber(version.Version); + } + + async removeImages(terminal: Terminal, nameMatches: string[], containersOnly: boolean): Promise { + // Stop and remove containers that belongs to images + const containerInfos = (await this.getContainerInfos()).filter((info) => { + return nameMatches.find(match => DevDocker.containersImageMatched(info, match)); + }); + for (let i = 0; i < containerInfos.length; i += 1) { + const info = containerInfos[i]; + progress(terminal, `Removing container [${DevDocker.containerTitle(info)}]`); + const container = this.client.getContainer(info.Id); + if (DevDocker.isRunning(info)) { + await container.stop(); + } + await container.remove(); + progressDone(terminal); + } + if (containersOnly) { + return; + } + // Remove images + const imageInfos = (await this.getImageInfos()).filter((info) => { + return nameMatches.find(match => DevDocker.imageHasMatchedName(info, match)); + }); + for (let i = 0; i < imageInfos.length; i += 1) { + const info = imageInfos[i]; + progress(terminal, `Removing image [${DevDocker.imageTitle(info)}]`); + const image = this.client.getImage(info.Id); + await image.remove(); + progressDone(terminal); + } + } + + async pull(terminal: Terminal, repoTag: string): Promise { + if (this.onBeforePull) { + await this.onBeforePull(repoTag); + } + const client = this.client; + const title = `Pulling [${repoTag}]`; + progress(terminal, title); + const image: Image = await new Promise((resolve, reject) => { + client.pull(repoTag, {}, function (err, stream) { + if (!stream) { + reject(err); + return; + } + client.modem.followProgress(stream, onFinished, onProgress); + + function onFinished(_err: any, output: any) { + resolve(output); + } + + function onProgress(event: any) { + progressLine(terminal, `${title}... ${event.progress || ''}`); + } + }); + }); + progress(terminal, title); + progressDone(terminal, ); + return image; + } + + async findImageInfo(name: string): Promise<(ImageInfo | null)> { + return (await this.getImageInfos()).find(x => DevDocker.imageHasMatchedName(x, name)) || null; + } + + async findContainerInfo(name: string): Promise { + return (await this.getContainerInfos()).find(x => DevDocker.hasName(x, name)) || null; + } + + async shutdownContainer(terminal: Terminal, def: ContainerDef, downTo: ContainerStatus) { + const info = await this.findContainerInfo(def.containerName); + if (!info) { + return; + } + if (downTo < ContainerStatus.running && DevDocker.isRunning(info)) { + progress(terminal, `Stopping [${def.containerName}]`); + await this.client.getContainer(info.Id).stop(); + progressDone(terminal, ); + this.dropCache(); + } + if (downTo < ContainerStatus.created) { + progress(terminal, `Removing [${def.containerName}]`); + await this.client.getContainer(info.Id).remove(); + progressDone(terminal); + this.dropCache(); + } + } + + async ensureImage(terminal: Terminal, requiredImage: string) { + if (!(await this.findImageInfo(requiredImage))) { + await this.pull(terminal, requiredImage); + this.dropCache(); + } + } + + async startupContainer(terminal: Terminal, def: ContainerDef, upTo: ContainerStatus) { + await this.ensureImage(terminal, def.requiredImage); + let info: ContainerInfo | null = await this.findContainerInfo(def.containerName); + if (upTo >= ContainerStatus.created && !info) { + progress(terminal, `Creating ${def.containerName}`); + await def.createContainer(this); + progressDone(terminal); + this.dropCache(); + info = await this.findContainerInfo(def.containerName); + } + if (upTo >= ContainerStatus.running && info && !DevDocker.isRunning(info)) { + progress(terminal, `Starting ${def.containerName}`); + await this.client.getContainer(info.Id).start(); + progressDone(terminal); + this.dropCache(); + } + } + + async shutdownContainers(terminal: Terminal, defs: ContainerDef[], downTo: ContainerStatus) { + for (let i = 0; i < defs.length; i += 1) { + await this.shutdownContainer(terminal, defs[i], downTo); + } + } + + async startupContainers(terminal: Terminal, defs: ContainerDef[], upTo: ContainerStatus) { + for (let i = 0; i < defs.length; i += 1) { + await this.startupContainer(terminal, defs[i], upTo); + } + } + + async ensureRunning(terminal: Terminal, def: ContainerDef): Promise { + await this.startupContainer(terminal, def, ContainerStatus.running); + const info = await this.findContainerInfo(def.containerName); + return this.client.getContainer((info && info.Id) || def.containerName); + } + + static hasName(container: ContainerInfo, name: string): boolean { + const nameToFind = `/${name}`.toLowerCase(); + return !!(container.Names || []).find(n => n.toLowerCase() === nameToFind); + } + + static imageTitle(info: ImageInfo): string { + return DevDocker.imageNames(info)[0] || info.Id; + } + + static containerTitle(info: ContainerInfo): string { + return info.Names.map(name => name.startsWith('/') ? name.substr(1) : name).join(';'); + } + + // if match specified with tag compare exactly + // if match specified without tag compare untagged names + static imageNameMatched(imageName: string, match: string): boolean { + imageName = imageName.toLowerCase(); + match = match.toLowerCase(); + const matchParts = match.split(':'); + if (matchParts.length > 1) { + return imageName === match; + } + const imageParts = imageName.split(':'); + return imageParts[0] === matchParts[0]; + } + + static imageNames(info: ImageInfo): string[] { + return [ + ...(info.RepoTags || []), + ...(info.RepoDigests || []).map((digest) => { + return digest.split('@').join(':'); + }), + ]; + } + + static imageHasMatchedName(info: ImageInfo, match: string): boolean { + return !!DevDocker.imageNames(info).find(name => this.imageNameMatched(name, match)); + } + + static isRunning(info: ContainerInfo | null): boolean { + return !!info && info.State.toLowerCase() === 'running'; + } + + static containersImageMatched(info: ContainerInfo, match: string): boolean { + return this.imageNameMatched(info.Image, match); + } +} + + +export { + DevDocker, +} diff --git a/src/controllers/se/index.ts b/src/controllers/se/index.ts new file mode 100644 index 0000000..4e428a4 --- /dev/null +++ b/src/controllers/se/index.ts @@ -0,0 +1,24 @@ +import { ToolController } from "../../core"; +import { + seInfoCommand, + seVersionCommand, + seUpdateCommand, + seSetCommand, + seResetCommand, + seStartCommand, + seStopCommand +} from "./commands"; + +export const SE: ToolController = { + name: "se", + title: "Node SE", + commands: [ + seInfoCommand, + seVersionCommand, + seUpdateCommand, + seSetCommand, + seStartCommand, + seStopCommand, + seResetCommand, + ], +}; diff --git a/src/controllers/se/installer.ts b/src/controllers/se/installer.ts new file mode 100644 index 0000000..5e2db96 --- /dev/null +++ b/src/controllers/se/installer.ts @@ -0,0 +1,173 @@ +import * as path from "path"; +import * as fs from "fs"; + +import { tondevHome } from "../../core"; +import { httpsGetJson, userIdentifier, versionToNumber } from "../../core/utils"; +import { ContainerDef, DevDocker } from "./docker"; +import Dockerode from "dockerode"; + +const DEFAULT_INSTANCE_NAME = "default"; +const DEFAULT_INSTANCE_PORT = 2020; +const DOCKER_IMAGE_NAME = "tonlabs/local-node"; +const DOCKER_CONTAINER_NAME_PREFIX = "tonlabs-tonos-se"; + +/** + * SE instance config + */ +type SEInstanceConfig = { + /** + * Instance name + */ + name: string, + /** + * Components version + */ + version: string, + /** + * Port on localhost used to expose GraphQL API + * GraphQL API is accessible through http://localhost:port/graphql + * Node Requests API is accessible through http://localhost:port/topics/requests + * Default value: 2020 + */ + port: number, + /** + * Port on localhost used to expose ArangoDB API + */ + dbPort?: number, + /** + * Optional port on localhost used to expose Node API + */ + nodePort?: number, +} + +type SEConfig = { + instances: SEInstanceConfig[], +} + +function compareVersions(a: string, b: string): number { + const an = versionToNumber(a); + const bn = versionToNumber(b); + return an < bn ? -1 : (an === bn ? 0 : 1); +} + +export async function getVersions(): Promise { + const url = `https://registry.hub.docker.com/v2/repositories/${DOCKER_IMAGE_NAME}/tags/`; + return (await httpsGetJson(url)).results.map((x: any) => x.name).sort(compareVersions); +} + +export async function getLatestVersion(): Promise { + const versions = await getVersions(); + const version = versions.pop(); + if (version && version.toLowerCase() !== "latest") { + return version; + } + return versions.pop() ?? ""; +} + +function configPath(): string { + return path.resolve(tondevHome(), "se", "config.json"); +} + +export async function getConfig(): Promise { + let config: SEConfig | null = null; + try { + if (fs.existsSync(configPath())) { + config = JSON.parse(fs.readFileSync(configPath(), "utf8")); + } + } catch { + } + if (!config) { + config = { instances: [] }; + } else if (!config.instances) { + config.instances = []; + } + if (config.instances.length === 0) { + config.instances.push({ + name: DEFAULT_INSTANCE_NAME, + port: DEFAULT_INSTANCE_PORT, + version: await getLatestVersion(), + }); + await setConfig(config); + } + return config; +} + +export async function setConfig(config: SEConfig) { + fs.writeFileSync(configPath(), JSON.stringify(config, undefined, " "), "utf8"); +} + +export function isInstanceMatched(instance: SEInstanceConfig, instanceFilter: string): boolean { + return instanceFilter === "*" || instanceFilter.toLowerCase() === instance.name.toLowerCase(); +} + +export async function filterInstances(instanceFilter: string): Promise { + const filtered: SEInstanceConfig[] = []; + for (const instance of (await getConfig()).instances) { + if (isInstanceMatched(instance, instanceFilter)) { + filtered.push(instance); + } + } + return filtered; +} + +export function instanceContainerDef(instance: SEInstanceConfig): ContainerDef { + const requiredImage = `${DOCKER_IMAGE_NAME}:${instance.version}`; + const suffix = instance.name !== DEFAULT_INSTANCE_NAME ? `-${instance.name}` : ''; + const containerName = `${DOCKER_CONTAINER_NAME_PREFIX}-${userIdentifier()}${suffix}`; + return { + requiredImage, + containerName, + createContainer(docker: DevDocker) { + const ports: Dockerode.PortMap = { + '80/tcp': [ + { + HostIp: '', + HostPort: `${instance.port}`, + }, + ], + }; + if (instance.dbPort) { + ports['8529/tcp'] = [ + { + HostIp: '', + HostPort: `${instance.dbPort}`, + }, + ] + } + return docker.client.createContainer({ + name: containerName, + // interactive: true, + Image: requiredImage, + Env: ['USER_AGREEMENT=yes'], + HostConfig: { + PortBindings: ports, + }, + }); + } + }; +} + +function mapContainerName(name: string): string { + return name.startsWith('/') ? name.substr(1) : name; +} + +type SEInstanceInfo = { + state: string, + docker: { + image: string, + container: string, + } +} + +export async function getInstanceInfo(docker: DevDocker, instance: SEInstanceConfig): Promise { + const def = instanceContainerDef(instance); + const info: Dockerode.ContainerInfo | null = await docker.findContainerInfo(def.containerName); + return { + state: info ? info.State : "not installed", + docker: { + image: info?.Image ?? def.requiredImage, + container: info?.Names.map(mapContainerName).join(', ') ?? def.containerName, + } + }; +} + diff --git a/src/core/utils.ts b/src/core/utils.ts index ad89e2d..6b43511 100644 --- a/src/core/utils.ts +++ b/src/core/utils.ts @@ -3,6 +3,7 @@ import * as os from "os"; import * as fs from "fs"; import { spawn, SpawnOptionsWithoutStdio } from "child_process"; import * as http from "http"; +import * as https from "https"; import * as zlib from "zlib"; import { Terminal } from "./index"; @@ -181,4 +182,84 @@ export function stringTerminal(): Terminal & { output: string, error: string } { this.write(`${args.map(x => `${x}`).join(" ")}\n`); }, }; -} \ No newline at end of file +} + +export function versionToNumber(s: string): number { + if (s.toLowerCase() === "latest") { + return 1_000_000_000; + } + const parts = `${s || ''}`.split('.').map(x => Number.parseInt(x)).slice(0, 3); + while (parts.length < 3) { + parts.push(0); + } + return parts[0] * 1000000 + parts[1] * 1000 + parts[2]; +} + +let _progressLine: string = ''; + +export function progressLine(terminal: Terminal, line: string) { + terminal.write(`\r${line}`); + const extra = _progressLine.length - line.length; + if (extra > 0) { + terminal.write(' '.repeat(extra) + '\b'.repeat(extra)); + } + _progressLine = line; +} + +export function progress(terminal: Terminal, info: string) { + progressLine(terminal, `${info}...`); +} + +export function progressDone(terminal: Terminal) { + terminal.log(' ✓'); + _progressLine = ''; +} + + +export function httpsGetJson(url: string): Promise { + return new Promise((resolve, reject) => { + const tryUrl = (url: string) => { + https.get(url, function (res) { + let body = ''; + + res.on('data', function (chunk) { + body += chunk; + }); + + res.on('end', function () { + if (res.statusCode === 301) { + const redirectUrl = res.headers['location']; + if (redirectUrl) { + tryUrl(redirectUrl); + } else { + reject(new Error("Redirect response has no `location` header.")); + } + return; + } + const response = JSON.parse(body); + resolve(response); + }); + }).on('error', (error) => { + reject(error); + }); + }; + tryUrl(url); + }) +} + +function toIdentifier(s: string): string { + let identifier = ""; + for (let i = 0; i < s.length; i += 1) { + const c = s[i]; + const isLetter = c.toLowerCase() !== c.toUpperCase(); + const isDigit = !isLetter && "0123456789".includes(c); + if (isLetter || isDigit) { + identifier += c; + } + } + return identifier; +} + +export function userIdentifier(): string { + return toIdentifier(os.userInfo().username).toLowerCase(); +} From 1af41ff3e530586c2cc6e571871e79fc2a934d44 Mon Sep 17 00:00:00 2001 From: Michael Vlasov Date: Thu, 25 Feb 2021 13:43:08 +0500 Subject: [PATCH 02/24] NEW: example to use tondev in JS apps NEW: snippet of JS usage in README.md --- .gitignore | 3 + README.md | 146 ++++++++++++++++++++++++-------------- examples/sol/Hello.sol | 36 ++++++++++ examples/sol/index.js | 10 +++ examples/sol/package.json | 5 ++ src/controllers/index.ts | 22 +++++- src/index.ts | 2 +- 7 files changed, 168 insertions(+), 56 deletions(-) create mode 100644 examples/sol/Hello.sol create mode 100644 examples/sol/index.js create mode 100644 examples/sol/package.json diff --git a/.gitignore b/.gitignore index 10cd9e5..3315bbc 100644 --- a/.gitignore +++ b/.gitignore @@ -105,3 +105,6 @@ dist /.idea/ /package-lock.json .vscode/launch.json +examples/sol/package-lock.json +examples/sol/Hello.abi.json +examples/sol/Hello.tvc diff --git a/README.md b/README.md index 566bdf7..4a570f1 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,44 @@ # TONDEV - Free TON Developer Environment -**Have a question? Get quick help in our channel:** +**Have a question? Get quick help in our channel:** [![Channel on Telegram](https://img.shields.io/badge/chat-on%20telegram-9cf.svg)](https://t.me/ton_sdk) -# Content Table -- [What is TONDEV](#what-is-tondev) +## Content Table + +- [TONDEV - Free TON Developer Environment](#tondev---free-ton-developer-environment) + - [Content Table](#content-table) + - [What is TONDEV?](#what-is-tondev) - [What components does it support?](#what-components-does-it-support) -- [Installation](#installation) -- [Supported commands](#supported-commands) + - [Installation](#installation) + - [Dependencies](#dependencies) + - [Install](#install) + - [Update](#update) + - [Use in JS applications](#use-in-js-applications) + - [Supported commands](#supported-commands) + - [General command syntax](#general-command-syntax) - [Solidity](#solidity) - [Create your first contract](#create-your-first-contract) - [Compile](#compile) - [Version](#version) - - [Update](#update) + - [Update](#update-1) - [SDK](#sdk) - [Create Demo Project](#create-demo-project) -- [TONDEV Extensibility](#tondev-extensibility) -- [Backlog](#backlog) - - [Solidity](#solidity) - - [C/C++](#cc) - - [TS4](#ts4) - - [SDK](#sdk) - - [Network Support](#network-support) + - [TONDEV Extensibility](#tondev-extensibility) + - [Backlog](#backlog) + - [Solidity](#solidity-1) + - [C/C++](#cc) + - [TS4](#ts4) + - [SDK](#sdk-1) + - [Network support](#network-support) + - [etc](#etc) -# What is TONDEV? -TONDEV an Node.js package with CLI interface that allows to easily download and install all the core TON.DEV components in background and use them from a single interface. -Also, this project serves as a backend for [TONDEV VS Code plugin](https://github.com/tonlabs/tondev-vscode). +## What is TONDEV? +TONDEV an Node.js package with CLI interface that allows to easily download and install all the core TON.DEV components in background and use them from a single interface. +Also, this project serves as a backend for [TONDEV VS Code plugin](https://github.com/tonlabs/tondev-vscode). -## What components does it support? +### What components does it support? These components are supported or will be supported soon. Each component is downloaded and installed automatically for the target platform upon the first request. @@ -41,30 +50,55 @@ Each component is downloaded and installed automatically for the target platform - [TestSuite4](https://github.com/tonlabs/TestSuite4) – SOON - [tonos-cli](https://github.com/tonlabs/tonos-cli) (installation only) – SOON -It can be extended with other tools following the [instructions of integration](#tondev-extensibility). +It can be extended with other tools following the [instructions of integration](#tondev-extensibility). -# Installation +## Installation -## Dependencies +### Dependencies - [`Node.js`](https://nodejs.org/) >= 10.x installed - (optional) [`Docker`](https://www.docker.com/) >= 19.x installed - Solidity compiler requires VC++ Runtime on Windows. You can install it from [the latest supported Visual C++ downloads](https://support.microsoft.com/en-us/topic/the-latest-supported-visual-c-downloads-2647da03-1eea-4433-9aff-95f26a218cc0). +#### Install + +```shell +npm i -g tondev +``` -**Install** +#### Update ```shell -$ npm i -g tondev +npm r -g tondev +npm i -g tondev ``` -**Update** + +## Use in JS applications + +You can easily use tondev as a regular npm package in your JS applications. + +Just add dependency into you `package.json`: ```shell -$ npm r -g tondev -$ npm i -g tondev +npm i -s tondev +``` + +And then run any command from tondev: + +```js +const { consoleTerminal, runCommand } = require("tondev"); +const path = require("path"); + +async function main() { + await runCommand(consoleTerminal, "sol compile", { + file: path.resolve(__dirname, "Hello.sol") + }); +} + +main(); ``` -# Supported commands +## Supported commands ```shell $ tondev @@ -79,54 +113,58 @@ Commands: ``` -**General command syntax** +### General command syntax ```shell -$ tondev ...args +tondev ...args ``` -# Solidity -## Create your first contract +## Solidity + +### Create your first contract + This command creates a hello-world Solidity contract with comments that you can observe and compile. ```shell -$ tondev sol create Contract +tondev sol create Contract ``` -## Compile +### Compile This command compiles and links a selected Solidity contract. After successful compilation you get .abi.json and .tvc files that you can later [use in your DApps to deploy and call contract methods](https://docs.ton.dev/86757ecb2/p/07f1a5-add-contract-to-your-app-/b/462f33). ```shell -$ tondev sol compile Contract.sol +tondev sol compile Contract.sol ``` -## Version +### Version + This command shows the currently installed Solidity compiler version. ```shell -$ tondev sol version +tondev sol version ``` -## Update -This command updates the compiler to the latest version. +### Update + +This command updates the compiler to the latest version. ```shell -$ tondev sol update +tondev sol update ``` -# SDK +## SDK -## Create Demo Project +### Create Demo Project This command creates a Node.js project with SDK latest dependencies and index.js file with main Client object creation. ```shell -$ tondev js create +tondev js create ``` -# TONDEV Extensibility +## TONDEV Extensibility TON Dev Environment is an integration point for development tools related to Free TON Blockchain. @@ -137,30 +175,32 @@ There are two kind of software connected to TONDev: Learn more about creating your own controller: [Creating Controller](docs/creating_controller.md) +## Backlog -# Backlog - -## Solidity +### Solidity -- syntax highligting - Q1 2021 -- support other compilation and linking options +- syntax highlighting - Q1 2021 +- support other compilation and linking options -## C/C++ +### C/C++ - Integrate C/C++ compiler - easily install and compile C/C++ contracts -## TS4 +### TS4 - debug contracts with TS framework and tools -## SDK -- Create and run Web Demo DApp with one command +### SDK + +- Create and run Web Demo DApp with one command + +### Network support -## Network support Q1 2021: + - Connect to networks: main.ton.dev, net.ton.dev, local network - Add a custom network - Setup network giver - Deploy to network -## etc.... +### etc diff --git a/examples/sol/Hello.sol b/examples/sol/Hello.sol new file mode 100644 index 0000000..3ad9f5c --- /dev/null +++ b/examples/sol/Hello.sol @@ -0,0 +1,36 @@ +pragma solidity >=0.5.0; +pragma AbiHeader time; +pragma AbiHeader expire; + +contract HelloTON { + uint32 timestamp; + + // Modifier that allows public function to accept all external calls. + modifier alwaysAccept { + tvm.accept(); + _; + } + modifier onlyOwner { + require(msg.pubkey() == tvm.pubkey(), 100); + tvm.accept(); + _; + } + + constructor() public { + tvm.accept(); + timestamp = uint32(now); + } + //Function setting set value to state variable timestamp + function touch() public alwaysAccept { + timestamp = uint32(now); + } + //Function returns value of state variable timestamp + function sayHello() public view returns (uint32) { + return timestamp; + } + //Due to the modifier onlyOwner function sendAllMoney can be called only by the owner of the contract. + //Function sendAllMoney send all contract's money to dest_addr. + function sendAllMoney(address dest_addr) public onlyOwner { + selfdestruct(dest_addr); + } +} diff --git a/examples/sol/index.js b/examples/sol/index.js new file mode 100644 index 0000000..26d1852 --- /dev/null +++ b/examples/sol/index.js @@ -0,0 +1,10 @@ +const { consoleTerminal, runCommand } = require("tondev"); +const path = require("path"); + +async function main() { + await runCommand(consoleTerminal, "sol compile", { + file: path.resolve(__dirname, "Hello.sol") + }); +} + +main(); diff --git a/examples/sol/package.json b/examples/sol/package.json new file mode 100644 index 0000000..b1534bf --- /dev/null +++ b/examples/sol/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "tondev": "file:../../" + } +} diff --git a/src/controllers/index.ts b/src/controllers/index.ts index 3fda0da..37e2db0 100644 --- a/src/controllers/index.ts +++ b/src/controllers/index.ts @@ -1,8 +1,26 @@ -import {Solidity} from "./solidity"; +import { Solidity } from "./solidity"; // import {TestSuite} from "./ts"; -import {JsApps} from "./js"; +import { JsApps } from "./js"; import { SE } from "./se"; +import { Terminal } from "../core"; export const controllers = [ Solidity, JsApps, SE, ]; + +export async function runCommand(terminal: Terminal, name: string, args: any): Promise { + const [controllerName, commandName] = name + .toLowerCase() + .split(" ") + .map(x => x.trim()) + .filter(x => x !== ""); + const controller = controllers.find(x => x.name === (controllerName || "")); + if (!controller) { + throw new Error(`Controller ${controllerName} not found`); + } + const command = controller.commands.find(x => x.name === (commandName || "")); + if (!command) { + throw new Error(`Command ${commandName} not found in controller ${controllerName}`); + } + await command.run(terminal, args); +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 94329dd..e3c125a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,3 @@ -export {controllers} from "./controllers/index"; +export {controllers, runCommand} from "./controllers/index"; export * from "./core/utils" export * from "./core/index" \ No newline at end of file From 0bb9ae8c4a9fd677f03b79de6c52eb63ec73ac67 Mon Sep 17 00:00:00 2001 From: Michael Vlasov Date: Thu, 25 Feb 2021 13:50:45 +0500 Subject: [PATCH 03/24] FIX: README.md --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 4a570f1..a821796 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,9 @@ - [What is TONDEV?](#what-is-tondev) - [What components does it support?](#what-components-does-it-support) - [Installation](#installation) - - [Dependencies](#dependencies) - - [Install](#install) - - [Update](#update) + - [Prerequisites](#prerequisites) + - [Install](#install) + - [Update](#update) - [Use in JS applications](#use-in-js-applications) - [Supported commands](#supported-commands) - [General command syntax](#general-command-syntax) @@ -54,19 +54,19 @@ It can be extended with other tools following the [instructions of integration]( ## Installation -### Dependencies +### Prerequisites - [`Node.js`](https://nodejs.org/) >= 10.x installed - (optional) [`Docker`](https://www.docker.com/) >= 19.x installed - Solidity compiler requires VC++ Runtime on Windows. You can install it from [the latest supported Visual C++ downloads](https://support.microsoft.com/en-us/topic/the-latest-supported-visual-c-downloads-2647da03-1eea-4433-9aff-95f26a218cc0). -#### Install +### Install ```shell npm i -g tondev ``` -#### Update +### Update ```shell npm r -g tondev From 9a4a00d36b70c4dd886293a39ccfe7c94bef3cbf Mon Sep 17 00:00:00 2001 From: Michael Vlasov Date: Thu, 25 Feb 2021 13:57:32 +0500 Subject: [PATCH 04/24] FIX: README --- README.md | 46 ++++++++++++++++------------------------------ 1 file changed, 16 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index a821796..f25c0fb 100644 --- a/README.md +++ b/README.md @@ -15,15 +15,15 @@ - [Install](#install) - [Update](#update) - [Use in JS applications](#use-in-js-applications) - - [Supported commands](#supported-commands) + - [Command Line Interface](#command-line-interface) - [General command syntax](#general-command-syntax) - - [Solidity](#solidity) - - [Create your first contract](#create-your-first-contract) - - [Compile](#compile) - - [Version](#version) - - [Update](#update-1) - - [SDK](#sdk) - - [Create Demo Project](#create-demo-project) + - [Solidity](#solidity) + - [Create your first contract](#create-your-first-contract) + - [Compile](#compile) + - [Version](#version) + - [Update](#update-1) + - [SDK](#sdk) + - [Create Demo Project](#create-demo-project) - [TONDEV Extensibility](#tondev-extensibility) - [Backlog](#backlog) - [Solidity](#solidity-1) @@ -98,30 +98,16 @@ async function main() { main(); ``` -## Supported commands - -```shell -$ tondev -Use: tondev command args... -Version: 0.1.4 -Commands: - sol create Create Solidity Contract - sol compile Compile Solidity Contract - sol version Show Solidity Version - sol update Update Solidity Compiler - js create Create TON JS App - -``` - +## Command Line Interface ### General command syntax ```shell tondev ...args ``` -## Solidity +### Solidity -### Create your first contract +#### Create your first contract This command creates a hello-world Solidity contract with comments that you can observe and compile. @@ -129,7 +115,7 @@ This command creates a hello-world Solidity contract with comments that you can tondev sol create Contract ``` -### Compile +#### Compile This command compiles and links a selected Solidity contract. After successful compilation you get .abi.json and .tvc files that you can later [use in your DApps to deploy and call contract methods](https://docs.ton.dev/86757ecb2/p/07f1a5-add-contract-to-your-app-/b/462f33). @@ -138,7 +124,7 @@ After successful compilation you get .abi.json and .tvc files that you can later tondev sol compile Contract.sol ``` -### Version +#### Version This command shows the currently installed Solidity compiler version. @@ -146,7 +132,7 @@ This command shows the currently installed Solidity compiler version. tondev sol version ``` -### Update +#### Update This command updates the compiler to the latest version. @@ -154,9 +140,9 @@ This command updates the compiler to the latest version. tondev sol update ``` -## SDK +### SDK -### Create Demo Project +#### Create Demo Project This command creates a Node.js project with SDK latest dependencies and index.js file with main Client object creation. From 7482c30c35331667718db4ebcd48545467d64202 Mon Sep 17 00:00:00 2001 From: elasticLove1 Date: Thu, 25 Feb 2021 12:51:34 +0300 Subject: [PATCH 05/24] logo --- README.md | 11 ++++++++--- assets/tondev-blue.png | Bin 0 -> 1055 bytes 2 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 assets/tondev-blue.png diff --git a/README.md b/README.md index f25c0fb..9754685 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,13 @@ -# TONDEV - Free TON Developer Environment +

+

TONDEV

+

Free TON Developer Environment

+ -**Have a question? Get quick help in our channel:** +**Get quick help in our telegram channel:** -[![Channel on Telegram](https://img.shields.io/badge/chat-on%20telegram-9cf.svg)](https://t.me/ton_sdk) +[![Channel on Telegram](https://img.shields.io/badge/chat-on%20telegram-9cf.svg)](https://t.me/ton_sdk) + +# TONDEV - Free TON Developer Environment ## Content Table diff --git a/assets/tondev-blue.png b/assets/tondev-blue.png new file mode 100644 index 0000000000000000000000000000000000000000..c26c73a5efbe5031f741dafaaf0506750c54d303 GIT binary patch literal 1055 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q4M;wBd$a>caTa()7Bes?T7WR4>omgzpde#$ zkh>GZx^prwfgF}}M_)$E)e-c?47?`(sx;TbZFuuLJ(K|Gdq2XgN=dwvNE-X-+ zwab#@s*s3RNcQaP?BGV{3rP=zOs?Kg`l3E#F$<@ocZ-`@s^(P3#?Az_A1lgrPA;r? zzE@wa?A`a->+K%a-YdSh^ZUH=1tD6s{6W2ZY@7xPifk%J8d@YK2rvsJIXLlnbTD!n zQbBNuV#=!vy~`8rHSbyq7d?^0X6~j~k2kirBvx(xlB)f3M^s(;I=&ydw)?-{uZuHW zBys-H*~yOfmMvsCXF`tr>y<|X!o6Rt{BXiAe|P_vH&2soon#JyeEQvEjqrDmDgO>& z`nz@i46pCjK6k?n!&~`Y#J?$@v1xtMIfyot0J_O`rEJG1q3gG{2Q9c}rv1Nf+p?PJ zw?FZ&co}ds`I_1Gi%JjvoN}`~^tS8x*DX(fYXod#-*KU@3XZurP)z=3%pFeq+zhk{F zNUrVoWu`8*w0rN*qzCD)&1>D*?tSuj{}*}Aou?{2YZl=ACS zLiLL67CBFCO5SQ6*}CE6#eci%u2 zACHOY&RbCsedlQZljO^%J+tku?x@?Q+!Jp#uSDFzk88Jk(jGQ5v%M|yCp#y9i5B0r zI_l>+&xhtWd%Al+Mn#y0KYbjTwqo_p3lHBEO}`fZXlduo>#rYvy#3YSf1)9h)2N;^w!d?P24!L%gB&$qr6?)T5}BzOm#Pdj{o2cm0+ypWOw_&kUZfelF{r G5}E*4Ubt=m literal 0 HcmV?d00001 From dc900d2a1f0bc30cd95aab755b84418b839d2365 Mon Sep 17 00:00:00 2001 From: elasticLove1 Date: Thu, 25 Feb 2021 21:09:25 +0300 Subject: [PATCH 06/24] Update tondev-blue.png --- assets/tondev-blue.png | Bin 1055 -> 1471 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/tondev-blue.png b/assets/tondev-blue.png index c26c73a5efbe5031f741dafaaf0506750c54d303..33a1a2528121d0db22857304f00ebb29fde7b90a 100644 GIT binary patch literal 1471 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q4M;wBd$a>caTa()7Bes?T7WR4>omgzpde#$ zkh>GZx^prwfgF}}M_)$E)e-c?47+6C*T^vIy7~kIYFOqf@Y4~_udA6=y(;?QR z8%p6*gpU+7&WKUyO6^LWvnFtYf5Kr_4)qC1-AS3nOx$`6kQ-SzC5zs^}q;2_zBUVGR3e67>b zllGeVXN~ST)1}L@>N1NvmVbY09<(g{d3q^dhpz-u;DvVY?AGJN5yUGpX8sPzIuqv* zcj@leyFZsrIlI%O{P29^a`&2QM$7phoQ(t~cpPf5VYJnFS*#uteCk{z2D1*(G(kOjQ@o{MXe?y)p!_CyX(gl1&=2OYdZBT-&h)T;^O;?g0H_n%#=teH@){;eyKoRe4pEN zPxExcd28P~KDzs@-qKuT@f)@&C#yBRWI7)$TV`FQ7d5xLOrlcn^18~u?flgf?K=a% z&5PKv#=49BTvyy_tH~?ptl85&r+xDKRoj<(+>1ZGd++%p8jrV^f85`4tefwJgVe+4 z86~3suKiYAcK?0v%FofkQj^o=%|mlF<0NYDNE@E{#v$@t?B=)9is{*LT^-Nw?pWQw z-2YCC?}b6~+yC+Oa;5C)?U&A}-+9FU?DK5XzFR=WoNa#TT@1>O6aH$Gz>j!|6V^<_{aUr5exiTL0BaYk}4D zuReMEZ*}-a-YN0TzwhN5qQ0OeSncV(!mSmBXJ5P4d3n2rygqcOrZ*?*{?7^D^VhDc zyt}+AeA&M0OZ@XoRMlo^e|%WJ>OkD}*sC*L?qA(&!Iy9UHM0KciVT~;Qs%B#0)efM zJ6FjDl>AtzyzXOjNbmQ0&u53`EWbLPYjvGNVETnAIoSa-(}Rx0e!cnR^@i=KpKP9o zUU~dYuW)<0*-x7qW7RdY*Pi-*xccuRzK71H#WR`sFUO8aC(>c+ZvZsPCm0HYO+1P6DpDUsC9z0@Yzjgc`_ouEB(98XWxJL z{9=J4j|Hy!)p5Ok^slW_e|VD@lM}o*L%F*_?^E8_|zDSy#N&l Mp00i_>zopr0FHEu6aWAK literal 1055 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q4M;wBd$a>caTa()7Bes?T7WR4>omgzpde#$ zkh>GZx^prwfgF}}M_)$E)e-c?47?`(sx;TbZFuuLJ(K|Gdq2XgN=dwvNE-X-+ zwab#@s*s3RNcQaP?BGV{3rP=zOs?Kg`l3E#F$<@ocZ-`@s^(P3#?Az_A1lgrPA;r? zzE@wa?A`a->+K%a-YdSh^ZUH=1tD6s{6W2ZY@7xPifk%J8d@YK2rvsJIXLlnbTD!n zQbBNuV#=!vy~`8rHSbyq7d?^0X6~j~k2kirBvx(xlB)f3M^s(;I=&ydw)?-{uZuHW zBys-H*~yOfmMvsCXF`tr>y<|X!o6Rt{BXiAe|P_vH&2soon#JyeEQvEjqrDmDgO>& z`nz@i46pCjK6k?n!&~`Y#J?$@v1xtMIfyot0J_O`rEJG1q3gG{2Q9c}rv1Nf+p?PJ zw?FZ&co}ds`I_1Gi%JjvoN}`~^tS8x*DX(fYXod#-*KU@3XZurP)z=3%pFeq+zhk{F zNUrVoWu`8*w0rN*qzCD)&1>D*?tSuj{}*}Aou?{2YZl=ACS zLiLL67CBFCO5SQ6*}CE6#eci%u2 zACHOY&RbCsedlQZljO^%J+tku?x@?Q+!Jp#uSDFzk88Jk(jGQ5v%M|yCp#y9i5B0r zI_l>+&xhtWd%Al+Mn#y0KYbjTwqo_p3lHBEO}`fZXlduo>#rYvy#3YSf1)9h)2N;^w!d?P24!L%gB&$qr6?)T5}BzOm#Pdj{o2cm0+ypWOw_&kUZfelF{r G5}E*4Ubt=m From 1537760788abe716524a8ee2396194e01b8969a0 Mon Sep 17 00:00:00 2001 From: Ekaterina Pantaz <52739957+elasticLove1@users.noreply.github.com> Date: Thu, 25 Feb 2021 21:10:03 +0300 Subject: [PATCH 07/24] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9754685..91c4104 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

+

TONDEV

Free TON Developer Environment

From b068b61a3b0e3308115a5a2f54009799af7e9760 Mon Sep 17 00:00:00 2001 From: elasticLove1 Date: Thu, 25 Feb 2021 21:12:40 +0300 Subject: [PATCH 08/24] Update tondev-blue.png --- assets/tondev-blue.png | Bin 1471 -> 873 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/tondev-blue.png b/assets/tondev-blue.png index 33a1a2528121d0db22857304f00ebb29fde7b90a..8efcbf5b409e4f5e74ce45c407cdb4c770b51109 100644 GIT binary patch delta 801 zcmdnb{gQ1$Xg$+EPZ!6K3dXm0WAmg#B^n;Sw}^C@mJsH!BVRS0wS;|(wnA5EVdSO; zhuzH^n9C9_yF8k-p=p-vmt99B&+XXM(Q?J-kE7Q)oAYb?>!(zj7T2U1^)X-pKmK@a z$*Q|~^#945lhyuTo7}*{I8jLNq+?z`9X1;}*R1VgJ`RPqe(&*jX-`UGuAu;ela6 z|B?1ba-ARQ{lONa=q)rdt=)gvs8>+B(&7K1zkKX>!#BqAB`!fx1a$ISwkt<}?`EIc zeBu?`-eV2tKUr**4tUv?v!&VMU#ZmYs+|@+Le5N4u8X7WT4H&nOe5{PW7mG?WAEF- zUR9F!sNeCiS53X_Zmp+RH#FXTe{n?_^Q@B7jmqhTMU^t&OFw=4`Jgx zdu4349a&vbY5Ao<sPA_6d~)@FA5PB*+0D4ut}6a;1fNW80DooojQG0Z=O=#N zPA}a1|F-SEgSzJPmj>p>pSxJPywv$TTi?58i}ixG>xEaC&$hi$R)1Jt|5ftu_Kn+T zem?W4?%d+UxBt^#ojkg`YRAlDe%r)nzy0xNo!$TTZT0b6|4w}&q@R?YI%`+NnknxW z7rtdL`BoCS{mJ={AI?2~bJG9fj>0+I(e)J@E$7%w`M394{k&rwJ<1E}jB1K&zbFWP zeSdNP_1B9-dmMgGesR0+^{=xj^&9JdFZso%+`Zg<-D%5Tyw$~jL;ueDCx6Cwm-+1L za)CB`3*R>8y%uNLy=&H-`_j7EHp}JJUq3d!*RbuG_~u>8|F*dq{8>|T{c7mDBGYFD z+gP?-U2pdO?O8MJ>q~1Qm1q9j%XYcaTa()7Bes?T7WR4>omgzpde#$ zkh>GZx^prwfgF}}M_)$E)e-c?47+6C*T^vIy7~kIYFOqf@Y4~_udA6=y(;?QR z8%p6*gpU+7&WKUyO6^LWvnFtYf5Kr_4)qC1-AS3nOx$`6kQ-SzC5zs^}q;2_zBUVGR3e67>b zllGeVXN~ST)1}L@>N1NvmVbY09<(g{d3q^dhpz-u;DvVY?AGJN5yUGpX8sPzIuqv* zcj@leyFZsrIlI%O{P29^a`&2QM$7phoQ(t~cpPf5VYJnFS*#uteCk{z2D1*(G(kOjQ@o{MXe?y)p!_CyX(gl1&=2OYdZBT-&h)T;^O;?g0H_n%#=teH@){;eyKoRe4pEN zPxExcd28P~KDzs@-qKuT@f)@&C#yBRWI7)$TV`FQ7d5xLOrlcn^18~u?flgf?K=a% z&5PKv#=49BTvyy_tH~?ptl85&r+xDKRoj<(+>1ZGd++%p8jrV^f85`4tefwJgVe+4 z86~3suKiYAcK?0v%FofkQj^o=%|mlF<0NYDNE@E{#v$@t?B=)9is{*LT^-Nw?pWQw z-2YCC?}b6~+yC+Oa;5C)?U&A}-+9FU?DK5XzFR=WoNa#TT@1>O6aH$Gz>j!|6V^<_{aUr5exiTL0BaYk}4D zuReMEZ*}-a-YN0TzwhN5qQ0OeSncV(!mSmBXJ5P4d3n2rygqcOrZ*?*{?7^D^VhDc zyt}+AeA&M0OZ@XoRMlo^e|%WJ>OkD}*sC*L?qA(&!Iy9UHM0KciVT~;Qs%B#0)efM zJ6FjDl>AtzyzXOjNbmQ0&u53`EWbLPYjvGNVETnAIoSa-(}Rx0e!cnR^@i=KpKP9o zUU~dYuW)<0*-x7qW7RdY*Pi-*xccuRzK71H#WR`sFUO8aC(>c+ZvZsPCm0HYO+1P6DpDUsC9z0@Yzjgc`_ouEB(98XWxJL z{9=J4j|Hy!)p5Ok^slW_e|VD@lM}o*L%F*_?^E8_|zDSy#N&l Mp00i_>zopr0FHEu6aWAK From db9630ffbbb5bd4099d7bf972bf97a8a72ad5d5b Mon Sep 17 00:00:00 2001 From: elasticLove1 Date: Thu, 25 Feb 2021 21:17:00 +0300 Subject: [PATCH 09/24] Create tondev-FT.svg --- assets/tondev-FT.svg | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 assets/tondev-FT.svg diff --git a/assets/tondev-FT.svg b/assets/tondev-FT.svg new file mode 100644 index 0000000..5c1b0bc --- /dev/null +++ b/assets/tondev-FT.svg @@ -0,0 +1,4 @@ + + + + From 87750131070c0c9b83aea8f66295438c1458fbf6 Mon Sep 17 00:00:00 2001 From: elasticLove1 Date: Thu, 25 Feb 2021 21:19:10 +0300 Subject: [PATCH 10/24] Create tondev-TB.png --- assets/tondev-TB.png | Bin 0 -> 1083 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/tondev-TB.png diff --git a/assets/tondev-TB.png b/assets/tondev-TB.png new file mode 100644 index 0000000000000000000000000000000000000000..fc7c0ee861f488443a35353e529f933a70148725 GIT binary patch literal 1083 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q4M;wBd$a>caTa()7Bes?T7WR4>omgzpde#$ zkh>GZx^prwfgF}}M_)$E)e-c?47?>}3x;TbZFuuLJKfgCnrs3n|Ro=Ib^-Bi| z3MCpPh?)sDOU#(~gPG@0(v*k@A08bxL(d}$Y-c=XbZiKj6|!Win{?*Vm;6`XPd%oz z_xU|{>F;~atG~Q*`I*}HmzDQ_?|W|h)+@YSY|@ow?^GDsRE{*XNK6o57D{q(;_>KU z$%C;{Z`o(>R!6MzV*jH5&HBvE@Qo>0oN$!w%jRp>OMJecNm;Zjefg}u zla;!2SKVp2_Kd}3YL%LM@b0X~^QHDLp1E^hkvyxG*@BtB=B+8*dsrVRai4ATF-zvs z1$XvW30+vW{rl!)XLHVV?-Ul5zVKyRZRF!?{rkM7?QFc(zLKxmR`KKXZuV)vqpSjV zGV;DTFDGs6nQQaDK%{D!TkzkrbKiViyJwnT@R#KqUN-L8|Hne`-nTEG9s&mi-LqgnClf@<6y}B_eQ0`+HEr`z2?_CslIFNmEE;v)&JMF ze6hm6PlJS*y8IoLkFQ(rG*;;8i^?r)6p3Jem8}2;}ziBV* z?fU3Z!qmf&K|j@ll^cF^MGFfC$GG&QN^SJZ$Smvnyv)MnsL;e2g-JChx2s1zG~4eK iBdklKj36;#Lj0V*dv2mox#)9&t;ucLK6TXaK%yp literal 0 HcmV?d00001 From fb96e07cd2f208f9381dbbb4dd3f01be65122ab7 Mon Sep 17 00:00:00 2001 From: elasticLove1 Date: Thu, 25 Feb 2021 21:27:10 +0300 Subject: [PATCH 11/24] Create tondev-ZT.png --- assets/tondev-ZT.png | Bin 0 -> 2011 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/tondev-ZT.png diff --git a/assets/tondev-ZT.png b/assets/tondev-ZT.png new file mode 100644 index 0000000000000000000000000000000000000000..018c7077151c52a5eaea4397d0f4eaf63c9cea5b GIT binary patch literal 2011 zcma)+dpy(s9>>3%sV2AIFY*hyY`GgN$>uT<#yX_c?1x;cjV%jp>c=uV2nXG$mEt!N za;ek^ji0bwTE9kClgo@rI&P`slFRnfIp@*i{CPf)$LsTYKHiVl`|)`H^M3!s-w&&% zqN@S`fSQlD2Y$m%HsrHq)5ibo{u~SdAnMcu2mGTBU=PI5V(3R=kDnxC$tsUo=5%=lE*Og7?ft^Zv}s`+xy3by!-4s@!~j?2qyh-wxLeVZtl zOZq5b%u2RiZLkhzOH9Dlx(^W_`o_4O6MVj7Tq~U*WI(R{;z`H_h}&uxRD5C?%6Fm_7>)hhUI!3=`Ca4l z6Jh?fJ(*#i*5;Kta{gfE=8y2jAjoFM=fTU)_V*uHzyzM%`>JmH!TXw1SCgN54oC3^ zQx9F?B3W7^N)3xQE$Qsh3{4JUd?+sSkqwpmLQ_F*q(bN6KnSntB3)%3!#_zl-=seo zS5fKE``oHrlpm=%k{W-u)%j(|tjAj2?yv%tvq|^@)d>v)KssiLs9`R_4QhO;mYIS} zM9RL-FPX~?6Wb%etXV`P)luAoE{(`?v!2bCefcS%9K$D8{C?AYJq%H=)nVe29$KIp z*M&U0wy<)JSeU}g!`m9e2N-@&|>AWjQM_k(|) zVcyI!3}5@!rSAQ$X$jNX$nb3*SB*5NiNWC|GVjO#Wy)nfAo~R zYihC=>0YLQf9|Plo1+lmO{z%=l&Z5m(1=*LXt$58Pj2e6J}hq>xx=``DA%m}2q}lu z>xfgg?_|Rmq_2&=q682e&vD3Z%AWkqtwSD3x+Sd@zQA!DH2a19!l;)w#L=OStY~63 z&ntk#d&l?`w<}Wj6e6x`KvYNKeq^x-ksK%7VFXH3P_$NldsJE%@t;9pR!Yae5h2Z#T6A93t*c_@@ zU1zesDv3sbh9ZTM!X$p{i<9pJ8wY|${?#YK*B7wd;4J_Iqzfo-5NJafklqjW0+|C! z|E_}pAcG1({+sdJ@b9mGL*IM;2py?EMy5%>`)|#>m%LFPiGetHM`y3MxraNIP~ot zhOisVDD;#by&8&XacdK9AC7#GO*Z|6viqXyy&}1S!9b0nkVVKkbpDCW6`~Goj|LVO z(0=qcT)ybqX+MiVwIj`JoISo{uib9(AW|etsAWdKDz7=cd41jlNRLRq9l}cb_G-E$ zC<>i;`MRS&lW$Qf_Vg^oSDOC6D8^d9^-r%k*@NbZZs)Hz{merT1R9otyP@xg6M}LI zgUhWwaK{Speip&XwDnWya!a`pv8ClzW$N*#4`K*Lb??_phaL>OSnNk+2(RU4y!qeh zT?kpR(RAGD(DI>jekzSFbvC(ZwG}U-&K+vYjo$iaYq&`H-WLro3e2r1ouLcGWtP371B$^hB;P! zfi{C7>};X2AaP1vGrfsja8;~X^NkKQNWUBMKuhnrnv6(mS+rkoLGQryqG1ME%!S;% z(MM{AhOU`isud$)=U|XEn;gYs{ZQ7xH}e(2)v@sQ77WC+G&cTo?t=D+L|?E@nz)Xv zUBVX6)tB87+Fq-;H=Z{3BKuCvdAs*V4rVzyqaK6Zn_|ezs4m0TNl{Vr`kAvGj&(!r zPH!xPg+y9fJy1s?UM1BH|Ii;xZl<%Um(e=jg zl?o3WWS+1peDd~y26KOd+WyfN`>bTfnT|z2o!S)d&>7FQ5^DuGJhC%}YsGT-z9T-K LejX3q!&CkOoRg!I literal 0 HcmV?d00001 From 85d49dd9cbd608357c11562db105db3e3a35e347 Mon Sep 17 00:00:00 2001 From: Ekaterina Pantaz <52739957+elasticLove1@users.noreply.github.com> Date: Thu, 25 Feb 2021 21:28:07 +0300 Subject: [PATCH 12/24] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 91c4104..b76e2b4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

+

TONDEV

Free TON Developer Environment

From eddf8c4ef56683129732449be91d1be1ec0d9cf0 Mon Sep 17 00:00:00 2001 From: elasticLove1 Date: Thu, 25 Feb 2021 23:17:02 +0300 Subject: [PATCH 13/24] update --- README.md | 18 ++++++++++++------ assets/tondev-FT.svg | 4 ---- assets/tondev-TB.png | Bin 1083 -> 0 bytes assets/tondev-blue.png | Bin 873 -> 0 bytes assets/{tondev-ZT.png => tondev.png} | Bin 5 files changed, 12 insertions(+), 10 deletions(-) delete mode 100644 assets/tondev-FT.svg delete mode 100644 assets/tondev-TB.png delete mode 100644 assets/tondev-blue.png rename assets/{tondev-ZT.png => tondev.png} (100%) diff --git a/README.md b/README.md index 91c4104..d9fba4b 100644 --- a/README.md +++ b/README.md @@ -40,22 +40,28 @@ ## What is TONDEV? -TONDEV an Node.js package with CLI interface that allows to easily download and install all the core TON.DEV components in background and use them from a single interface. -Also, this project serves as a backend for [TONDEV VS Code plugin](https://github.com/tonlabs/tondev-vscode). +TONDEV is a Node.js package with CLI interface that allows to easily download and install all the core TON.DEV components in background and use them from a single interface. +Also, this project serves as a backend for [TONDEV VS Code extension](https://github.com/tonlabs/tondev-vscode). ### What components does it support? These components are supported or will be supported soon. Each component is downloaded and installed automatically for the target platform upon the first request. +- [Debot](https://docs.ton.dev/86757ecb2/p/72f1b7-debot-specifications) - SOON + Support of debot test chat(browser for debot testing), debot publishing, etc. - [Solidity Compiler](https://github.com/tonlabs/TON-Solidity-Compiler) -- [TON-SDK](https://github.com/tonlabs/TON-SDK) - [C/C++ Compiler](https://github.com/tonlabs/TON-Compiler) - SOON -- [TON OS Startup Edition](https://github.com/tonlabs/tonos-se) – SOON -- [TestSuite4](https://github.com/tonlabs/TestSuite4) – SOON +- [TON OS Startup Edition](https://github.com/tonlabs/tonos-se) – + Local blockchain for development and testing +- [TestSuite4](https://github.com/tonlabs/TestSuite4) – +Python lightweight framework for Solidity testing - [tonos-cli](https://github.com/tonlabs/tonos-cli) (installation only) – SOON + TONOS Client Application with CLI interface +- [TON-SDK](https://github.com/tonlabs/TON-SDK) + Core SDK Library. We plan to add some useful functionality like keys generation, address conversion, support of deploy, get methods, etc. from CLI and IDE -It can be extended with other tools following the [instructions of integration](#tondev-extensibility). +TONDEV can be extended with other tools following the [instructions of integration](#tondev-extensibility). ## Installation diff --git a/assets/tondev-FT.svg b/assets/tondev-FT.svg deleted file mode 100644 index 5c1b0bc..0000000 --- a/assets/tondev-FT.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/assets/tondev-TB.png b/assets/tondev-TB.png deleted file mode 100644 index fc7c0ee861f488443a35353e529f933a70148725..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1083 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q4M;wBd$a>caTa()7Bes?T7WR4>omgzpde#$ zkh>GZx^prwfgF}}M_)$E)e-c?47?>}3x;TbZFuuLJKfgCnrs3n|Ro=Ib^-Bi| z3MCpPh?)sDOU#(~gPG@0(v*k@A08bxL(d}$Y-c=XbZiKj6|!Win{?*Vm;6`XPd%oz z_xU|{>F;~atG~Q*`I*}HmzDQ_?|W|h)+@YSY|@ow?^GDsRE{*XNK6o57D{q(;_>KU z$%C;{Z`o(>R!6MzV*jH5&HBvE@Qo>0oN$!w%jRp>OMJecNm;Zjefg}u zla;!2SKVp2_Kd}3YL%LM@b0X~^QHDLp1E^hkvyxG*@BtB=B+8*dsrVRai4ATF-zvs z1$XvW30+vW{rl!)XLHVV?-Ul5zVKyRZRF!?{rkM7?QFc(zLKxmR`KKXZuV)vqpSjV zGV;DTFDGs6nQQaDK%{D!TkzkrbKiViyJwnT@R#KqUN-L8|Hne`-nTEG9s&mi-LqgnClf@<6y}B_eQ0`+HEr`z2?_CslIFNmEE;v)&JMF ze6hm6PlJS*y8IoLkFQ(rG*;;8i^?r)6p3Jem8}2;}ziBV* z?fU3Z!qmf&K|j@ll^cF^MGFfC$GG&QN^SJZ$Smvnyv)MnsL;e2g-JChx2s1zG~4eK iBdklKj36;#Lj0V*dv2mox#)9&t;ucLK6TXaK%yp diff --git a/assets/tondev-blue.png b/assets/tondev-blue.png deleted file mode 100644 index 8efcbf5b409e4f5e74ce45c407cdb4c770b51109..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 873 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q4M;wBd$a>caTa()7Bes?T7WR4>omgzpde#$ zkh>GZx^prwfgF}}M_)$E)e-c?47?}Qfx;TbZFuuJTn~7w`T$XUz<^dTOZpWsMmMcDg9KFujoL}2t zKc&*NxF*f04`>Sp`0>YUOIF>@qyJCdoUHc$+T;cn#)(P_K`bs^4IY95noLTr4olv+ zZ{8JpCweBI^!C%)+gIM5`Xcs>{=K`hfxXY)yc9p!<}3kG$I&5zsTsH6r4ReRzImeM zwZ_hJ(d?REg$xf23;K_=Ka%VG;19MJMQfpvY3=^QM!ka4l@9+8{pDl78@@4?FL4Qq zBA|=kvRyg)dpG;k<`b{j_8x0E|H)#jbim8DoGr~3|4OBHSM9Xu5prgVa$Ou{*AmMs zWg2PU9lQ2BAA8>x_NtP+NBxeEy=r84YdyWXq4Dnfiz~{QXO*08R8B7}s+9R&`sv%x z2gM1gn>yUKN?)kjD`T_m$m)tp%P$2YAMYkbeYdmcldJ#xaC%0_ZpOWKRq=--_+)AW z_$#|-#Mc!+Kk@T+dg0#xw{7KG%z>*+{M!6rOxNs`rb8LtQWLhFTBEhw(X6w z!}9vCl7F{v+&=U3nMZZ!7AL;_pZ4nH(cM)$W*+m~CO-S^k3Z||{I)(L zr1aETyCT+1dB3>uEqlqglF02(&VT%H?(v(G{ug%?&f$)(uh?ig$7agEz1QmJ9pmUx zUQlOLQ(XH+LGbJQi~Fy?UL4xv@O$!$+kLNpolU9V_Ro&9+%Cum1Y6@x6v^&%`(HQvSEi&EU_P zn(J3X-xZlYE7-=e Date: Thu, 25 Feb 2021 23:19:00 +0300 Subject: [PATCH 14/24] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2d1a0dd..a2636c5 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

+

TONDEV

Free TON Developer Environment

From c5a5d0cf42e2bca1365a132eed491de882fa6ada Mon Sep 17 00:00:00 2001 From: Ekaterina Pantaz <52739957+elasticLove1@users.noreply.github.com> Date: Thu, 25 Feb 2021 23:35:47 +0300 Subject: [PATCH 15/24] Update README.md --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a2636c5..aab0bdf 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,18 @@

TONDEV

-

Free TON Developer Environment

+

Free TON Development Environment

**Get quick help in our telegram channel:** [![Channel on Telegram](https://img.shields.io/badge/chat-on%20telegram-9cf.svg)](https://t.me/ton_sdk) -# TONDEV - Free TON Developer Environment +# TONDEV - Free TON Development Environment +Download and install all the core TON.DEV components in one click and access them from a single interface. ## Content Table -- [TONDEV - Free TON Developer Environment](#tondev---free-ton-developer-environment) +- [TONDEV - Free TON Development Environment](#tondev---free-ton-development-environment) - [Content Table](#content-table) - [What is TONDEV?](#what-is-tondev) - [What components does it support?](#what-components-does-it-support) From c884d6f460e63fd3f22de3c293ebd009c4d38638 Mon Sep 17 00:00:00 2001 From: Ekaterina Pantaz <52739957+elasticLove1@users.noreply.github.com> Date: Thu, 25 Feb 2021 23:49:23 +0300 Subject: [PATCH 16/24] Update README.md --- README.md | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index aab0bdf..11fb4ad 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@

TONDEV

Free TON Development Environment

+

**Get quick help in our telegram channel:** @@ -8,7 +9,7 @@ [![Channel on Telegram](https://img.shields.io/badge/chat-on%20telegram-9cf.svg)](https://t.me/ton_sdk) # TONDEV - Free TON Development Environment -Download and install all the core TON.DEV components in one click and access them from a single interface. +Download and install all the core [TON.DEV](https://docs.ton.dev/86757ecb2/p/04a4ba-) components in one click and access them from a single interface. ## Content Table @@ -32,6 +33,7 @@ Download and install all the core TON.DEV components in one click and access the - [Create Demo Project](#create-demo-project) - [TONDEV Extensibility](#tondev-extensibility) - [Backlog](#backlog) + - [Debot](#debot) - [Solidity](#solidity-1) - [C/C++](#cc) - [TS4](#ts4) @@ -49,18 +51,17 @@ Also, this project serves as a backend for [TONDEV VS Code extension](https://gi These components are supported or will be supported soon. Each component is downloaded and installed automatically for the target platform upon the first request. -- [Debot](https://docs.ton.dev/86757ecb2/p/72f1b7-debot-specifications) - SOON - Support of debot test chat(browser for debot testing), debot publishing, etc. +- [Debot](https://docs.ton.dev/86757ecb2/p/72f1b7-debot-specifications) - **SOON** - [Solidity Compiler](https://github.com/tonlabs/TON-Solidity-Compiler) -- [C/C++ Compiler](https://github.com/tonlabs/TON-Compiler) - SOON +- [C/C++ Compiler](https://github.com/tonlabs/TON-Compiler) - **SOON** - [TON OS Startup Edition](https://github.com/tonlabs/tonos-se) – Local blockchain for development and testing -- [TestSuite4](https://github.com/tonlabs/TestSuite4) – -Python lightweight framework for Solidity testing -- [tonos-cli](https://github.com/tonlabs/tonos-cli) (installation only) – SOON - TONOS Client Application with CLI interface -- [TON-SDK](https://github.com/tonlabs/TON-SDK) - Core SDK Library. We plan to add some useful functionality like keys generation, address conversion, support of deploy, get methods, etc. from CLI and IDE +- [TestSuite4](https://github.com/tonlabs/TestSuite4) – **SOON** + Python lightweight framework for Solidity testing +- [tonos-cli](https://github.com/tonlabs/tonos-cli) – **SOON** (installation only) + Command line tool for TON OS +- [TON-SDK](https://github.com/tonlabs/TON-SDK) - **SOON** + Core SDK Library features. TONDEV can be extended with other tools following the [instructions of integration](#tondev-extensibility). @@ -175,10 +176,13 @@ Learn more about creating your own controller: [Creating Controller](docs/creati ## Backlog +### Debot +- Support of debot test chat(browser for debot testing), +- Debot publishing, etc. + ### Solidity -- syntax highlighting - Q1 2021 -- support other compilation and linking options +- Support other compilation and linking options ### C/C++ @@ -186,11 +190,18 @@ Learn more about creating your own controller: [Creating Controller](docs/creati ### TS4 -- debug contracts with TS framework and tools +- Debug contracts with TS framework and tools ### SDK - Create and run Web Demo DApp with one command +- Generate keys +- Calculate addresses +- Estimate deploy fees +- Deploy contracts, +- Run on-chain methods +- Run get-methods +- Convert addresses, etc. ### Network support @@ -199,6 +210,3 @@ Q1 2021: - Connect to networks: main.ton.dev, net.ton.dev, local network - Add a custom network - Setup network giver -- Deploy to network - -### etc From 0aed107e811610a7fb1036c4a75d6430b55b88cd Mon Sep 17 00:00:00 2001 From: Michael Vlasov Date: Fri, 26 Feb 2021 11:55:38 +0500 Subject: [PATCH 17/24] NEW: print usage format NEW: se info format FIX: se commands failed when tondev home folder is missing. --- src/cli/index.ts | 46 ++++++++++++++------------------- src/controllers/js/index.ts | 2 +- src/controllers/se/commands.ts | 46 +++++++++++++++++++-------------- src/controllers/se/index.ts | 2 +- src/controllers/se/installer.ts | 4 +++ src/core/utils.ts | 24 +++++++++++++++++ 6 files changed, 77 insertions(+), 47 deletions(-) diff --git a/src/cli/index.ts b/src/cli/index.ts index 0670754..5a4375e 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -1,6 +1,6 @@ import { Command, CommandArg, ToolController } from "../core"; import { controllers } from "../controllers"; -import { consoleTerminal } from "../core/utils"; +import { consoleTerminal, formatTable } from "../core/utils"; import * as fs from "fs"; import * as path from "path"; @@ -70,45 +70,39 @@ export function printCommandUsage(controller: ToolController, command: Command) console.log(`Use: tondev ${controller.name} ${command.name}${usageArgs}`); if (args.length > 0) { console.log("Args:"); - let colWidth = options.reduce((w, x) => Math.max(w, x.name.length), 0); - args.forEach(x => { - console.log(` ${x.name.padEnd(colWidth)} ${x.title ?? ""}`); - }); + console.log(formatTable(args.map(x => [" ", x.name, x.title]))); } console.log("Options:"); console.log(` --help, -h Show command usage`); - let colWidth = options.reduce((w, x) => Math.max(w, x.name.length), 0); - options.forEach(x => { - console.log(` --${x.name.padEnd(colWidth)} ${x.title ?? ""}`); - }); + console.log(formatTable(options.map(x => [" ", `--${x.name}`, x.title]))); return; } -export function printUsage(useController?: ToolController, useCommand?: Command) { +export function printControllerUsage(controller: ToolController) { + const commands: [string, Command][] = controller.commands + .map(x => [`${controller.name} ${x.name}`, x]); + console.log(formatTable(commands.map(x => [" ", x[0], x[1].title]))); +} + +export function printUsage(controller?: ToolController, command?: Command) { const pkg = JSON.parse(fs.readFileSync(path.resolve(__dirname, "..", "..", "package.json"), "utf8")); console.log(`TONDev Version: ${pkg.version}`); - if (useController && useCommand) { - printCommandUsage(useController, useCommand); + if (controller && command) { + printCommandUsage(controller, command); return; } - console.log(`Use: tondev ${useController?.name ?? "tool"} ${useCommand?.name ?? "command"} args [options]`); + console.log(`Use: tondev ${controller?.name ?? "tool"} ${command?.name ?? "command"} args [options]`); console.log(`Options:`); console.log(` --help, -h Show command usage`); - console.log("Commands:"); - const commands: [string, Command][] = []; + if (controller) { + console.log("Commands:"); + printControllerUsage(controller); + return; + } for (const controller of controllers) { - for (const command of controller.commands) { - if ((useController === undefined || useController === controller) - && (useCommand === undefined || useCommand === command)) { - commands.push([`${controller.name} ${command.name}`, command]) - } - } + console.log(`\n${controller.title ?? controller.name} Commands:\n`); + printControllerUsage(controller); } - let colWidth = commands.reduce((w, x) => Math.max(w, x[0].length), 0); - commands.forEach(x => { - console.log(` ${x[0].padEnd(colWidth)} ${x[1].title ?? ""}`); - }); - return; } function missingArgError(arg: CommandArg): Error { diff --git a/src/controllers/js/index.ts b/src/controllers/js/index.ts index c1efa8c..6e53a0e 100644 --- a/src/controllers/js/index.ts +++ b/src/controllers/js/index.ts @@ -3,6 +3,6 @@ import {ToolController} from "../../core"; export const JsApps: ToolController = { name: "js", - title: "JS TON Applications", + title: "JS Apps", commands: [jsCreateCommand], }; diff --git a/src/controllers/se/commands.ts b/src/controllers/se/commands.ts index d455740..1c5feff 100644 --- a/src/controllers/se/commands.ts +++ b/src/controllers/se/commands.ts @@ -10,6 +10,7 @@ import { } from "./installer"; import { Command, CommandArg, Terminal } from "../../core"; import { ContainerDef, ContainerStatus, DevDocker } from "./docker"; +import { formatTable } from "../../core/utils"; export const instanceArg: CommandArg = { name: "instance", @@ -26,38 +27,45 @@ async function controlInstances( await control(new DevDocker(), defs); } - export const seInfoCommand: Command = { name: "info", - title: "Show TON SE Info", + title: "Show SE Info", args: [instanceArg], async run(terminal: Terminal, args: { instance: string }): Promise { const docker = new DevDocker(); + const table: any[][] = [[ + "Instance", + "State", + "Version", + "GraphQL Port", + "ArangoDB Port", + "Docker Container", + "Docker Image", + ]] for (const instance of await filterInstances(args.instance)) { const info = await getInstanceInfo(docker, instance); - terminal.log(`${instance.name}: ${info.state}`); - terminal.log(` Config: --version ${instance.version} --port ${instance.port} --db-port ${instance.dbPort ?? "none"}`); - terminal.log(` Docker: ${info.docker.container} (${info.docker.image})`); + table.push([ + instance.name, + info.state, + instance.version, + instance.port, + instance.dbPort, + info.docker.container, + info.docker.image, + ]); } + terminal.log(formatTable(table, { headerSeparator: true })) }, }; export const seVersionCommand: Command = { name: "version", - title: "Show Node SE Version", - args: [{ - name: "available", - type: "string", - defaultValue: "false", - title: "Show available versions", - }], - async run(terminal: Terminal, args: { available: string }): Promise { + title: "Show SE Versions", + async run(terminal: Terminal, _args: {}): Promise { for (const instance of (await getConfig()).instances) { terminal.log(`${instance.name}: ${instance.version}`); } - if (args.available === "true") { - terminal.log(`Available: ${(await getVersions()).join(", ")}`); - } + terminal.log(`Available Versions: ${(await getVersions()).join(", ")}`); }, }; @@ -148,7 +156,7 @@ export const seSetCommand: Command = { }): Promise { const config = await getConfig(); const docker = new DevDocker(); - + let version: string | undefined = undefined; if (args.version !== "") { if (args.version.toLowerCase() === "latest") { @@ -160,7 +168,7 @@ export const seSetCommand: Command = { version = args.version; } } - + let port: number | undefined = undefined; if (args.port !== "") { port = Number.parseInt(args.port); @@ -168,7 +176,7 @@ export const seSetCommand: Command = { throw new Error(`Invalid port: ${args.port}`); } } - + let dbPort: number | "none" | undefined = undefined; if (args["db-port"] !== "") { if (args["db-port"].toLowerCase() === "none") { diff --git a/src/controllers/se/index.ts b/src/controllers/se/index.ts index 4e428a4..81dd110 100644 --- a/src/controllers/se/index.ts +++ b/src/controllers/se/index.ts @@ -11,7 +11,7 @@ import { export const SE: ToolController = { name: "se", - title: "Node SE", + title: "SE", commands: [ seInfoCommand, seVersionCommand, diff --git a/src/controllers/se/installer.ts b/src/controllers/se/installer.ts index 5e2db96..c5a9f81 100644 --- a/src/controllers/se/installer.ts +++ b/src/controllers/se/installer.ts @@ -93,6 +93,10 @@ export async function getConfig(): Promise { } export async function setConfig(config: SEConfig) { + const configDir = path.dirname(configPath()); + if (!fs.existsSync(configDir)) { + fs.mkdirSync(configDir, { recursive: true }); + } fs.writeFileSync(configPath(), JSON.stringify(config, undefined, " "), "utf8"); } diff --git a/src/core/utils.ts b/src/core/utils.ts index 6b43511..fc85d0a 100644 --- a/src/core/utils.ts +++ b/src/core/utils.ts @@ -263,3 +263,27 @@ function toIdentifier(s: string): string { export function userIdentifier(): string { return toIdentifier(os.userInfo().username).toLowerCase(); } + +function toString(value: any): string { + return value === null || value === undefined ? "" : value.toString(); +} + +export function formatTable(rows: any[][], options?: { headerSeparator?: boolean }): string { + const widths: number[] = []; + const updateWidth = (value: any, i: number) => { + const width = toString(value).length; + while (widths.length <= i) { + widths.push(0); + } + widths[i] = Math.max(widths[i], width); + }; + rows.forEach(x => x.forEach(updateWidth)); + const formatValue = (value: any, i: number) => toString(value).padEnd(widths[i]); + const formatRow = (row: any[]) => row.map(formatValue).join(" ").trimEnd(); + const lines = rows.map(formatRow); + if (options?.headerSeparator) { + const separator = formatRow(widths.map(x => "-".repeat(x))); + lines.splice(1, 0, separator); + } + return lines.join("\n"); +} From 5259faa1a83a3a527ba40ceb48795bf79c263e39 Mon Sep 17 00:00:00 2001 From: elasticLove1 Date: Fri, 26 Feb 2021 12:34:31 +0300 Subject: [PATCH 18/24] tonos se docs --- .gitignore | 1 + README.md | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 3315bbc..7033300 100644 --- a/.gitignore +++ b/.gitignore @@ -108,3 +108,4 @@ dist examples/sol/package-lock.json examples/sol/Hello.abi.json examples/sol/Hello.tvc +README.html diff --git a/README.md b/README.md index 11fb4ad..a150ad2 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,14 @@ Download and install all the core [TON.DEV](https://docs.ton.dev/86757ecb2/p/04a - [Compile](#compile) - [Version](#version) - [Update](#update-1) + - [TON OS Startup Edition(SE)](#ton-os-startup-editionse) + - [Start](#start) + - [Version](#version-1) + - [Set](#set) + - [Reset](#reset) + - [Update](#update-2) + - [Stop](#stop) + - [Info](#info) - [SDK](#sdk) - [Create Demo Project](#create-demo-project) - [TONDEV Extensibility](#tondev-extensibility) @@ -39,7 +47,6 @@ Download and install all the core [TON.DEV](https://docs.ton.dev/86757ecb2/p/04a - [TS4](#ts4) - [SDK](#sdk-1) - [Network support](#network-support) - - [etc](#etc) ## What is TONDEV? @@ -153,6 +160,64 @@ This command updates the compiler to the latest version. tondev sol update ``` +### TON OS Startup Edition(SE) + +#### Start +This command starts the TON OS SE container (Docker must be launched). When executed for the first time downloads the latest SE image +from dockerhub. + +```shell +tondev se start +``` + +#### Version +This command shows the default TON OS SE version and list of other available versions. + +```shell +tondev se version + +default: 0.24.12 +Available Versions: 0, 0.24, 0.24.5, 0.24.6, 0.24.8, 0.24.9, 0.24.10, 0.24.11, 0.24.12, latest +``` + +#### Set +This command switches tonon se to the specified version and downloads it, it is missing. + +```shell +tondev se set 0.24.11 +``` + +#### Reset +This command resets the TON OS SE container (Docker must be launched) - restarts it from scratch with a clean database. + +```shell +tondev se reset +``` +#### Update +This command downloads the latest TON OS SE image (Docker must be launched) and starts it. + +```shell +tondev se update +``` + +#### Stop +This command stops TON OS SE container. + +```shell +tondev se stop +``` + +#### Info +This command shows info about the downloaded versions. + +```shell +tondev se info + +Instance State Version GraphQL Port ArangoDB Port Docker Container Docker Image +-------- ------- ------- ------------ ------------- -------------------------- -------------------------- +default running 0.24.12 2020 tonlabs-tonos-se-ekaterina tonlabs/local-node:0.24.12 +``` + ### SDK #### Create Demo Project From a8c2701c420eccf2d02976f0ee5735bab2991ac9 Mon Sep 17 00:00:00 2001 From: Michael Vlasov Date: Fri, 26 Feb 2021 14:55:39 +0500 Subject: [PATCH 19/24] FIX: default graphql port has changed to 80 FIX: instance filter validates specified names FIX: set command suggests if user has not specified any parameter --- src/cli/index.ts | 3 ++ src/controllers/se/commands.ts | 55 +++++++++++++++++---------------- src/controllers/se/installer.ts | 28 ++++++++++------- 3 files changed, 49 insertions(+), 37 deletions(-) diff --git a/src/cli/index.ts b/src/cli/index.ts index 5a4375e..a5fb1eb 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -115,6 +115,9 @@ function getArgValue(arg: CommandArg, commandLine: CommandLine): string | undefi if (value !== undefined) { return value; } + if (arg.defaultValue !== undefined) { + return arg.defaultValue; + } throw missingArgError(arg); } let value = commandLine.options[arg.name]; diff --git a/src/controllers/se/commands.ts b/src/controllers/se/commands.ts index 1c5feff..6ebded8 100644 --- a/src/controllers/se/commands.ts +++ b/src/controllers/se/commands.ts @@ -1,11 +1,11 @@ import { + filterConfigInstances, filterInstances, getConfig, getInstanceInfo, getLatestVersion, getVersions, instanceContainerDef, - isInstanceMatched, setConfig } from "./installer"; import { Command, CommandArg, Terminal } from "../../core"; @@ -13,6 +13,7 @@ import { ContainerDef, ContainerStatus, DevDocker } from "./docker"; import { formatTable } from "../../core/utils"; export const instanceArg: CommandArg = { + isArg: true, name: "instance", type: "string", defaultValue: "*", @@ -23,7 +24,7 @@ async function controlInstances( instanceFilter: string, control: (docker: DevDocker, defs: ContainerDef[]) => Promise ): Promise { - const defs: ContainerDef[] = (await filterInstances(instanceFilter)).map(instanceContainerDef); + const defs: ContainerDef[] = (await filterConfigInstances(instanceFilter)).map(instanceContainerDef); await control(new DevDocker(), defs); } @@ -42,7 +43,7 @@ export const seInfoCommand: Command = { "Docker Container", "Docker Image", ]] - for (const instance of await filterInstances(args.instance)) { + for (const instance of await filterConfigInstances(args.instance)) { const info = await getInstanceInfo(docker, instance); table.push([ instance.name, @@ -111,13 +112,11 @@ export const seUpdateCommand: Command = { const config = await getConfig(); const latestVersion = await getLatestVersion(); const docker = new DevDocker(); - for (const instance of config.instances) { - if (isInstanceMatched(instance, args.instance)) { - instance.version = latestVersion; - const def = instanceContainerDef(instance); - await docker.shutdownContainer(terminal, def, ContainerStatus.missing); - await docker.startupContainer(terminal, def, ContainerStatus.created); - } + for (const instance of filterInstances(config.instances, args.instance)) { + instance.version = latestVersion; + const def = instanceContainerDef(instance); + await docker.shutdownContainer(terminal, def, ContainerStatus.missing); + await docker.startupContainer(terminal, def, ContainerStatus.created); } setConfig(config); }, @@ -189,23 +188,27 @@ export const seSetCommand: Command = { } } - for (const instance of config.instances) { - if (isInstanceMatched(instance, args.instance)) { - if (version !== undefined) { - instance.version = version; - } - if (port !== undefined) { - instance.port = port; - } - if (dbPort === "none") { - delete instance.dbPort; - } else if (dbPort !== undefined) { - instance.dbPort = dbPort; - } - const def = instanceContainerDef(instance); - await docker.shutdownContainer(terminal, def, ContainerStatus.missing); - await docker.startupContainer(terminal, def, ContainerStatus.created); + const instances = filterInstances(config.instances, args.instance); + + if (version === undefined && port === undefined && dbPort === undefined) { + throw new Error("There is nothing to set. You have to specify at least one config parameter. See command help."); + } + + for (const instance of instances) { + if (version !== undefined) { + instance.version = version; + } + if (port !== undefined) { + instance.port = port; + } + if (dbPort === "none") { + delete instance.dbPort; + } else if (dbPort !== undefined) { + instance.dbPort = dbPort; } + const def = instanceContainerDef(instance); + await docker.shutdownContainer(terminal, def, ContainerStatus.missing); + await docker.startupContainer(terminal, def, ContainerStatus.created); } setConfig(config); }, diff --git a/src/controllers/se/installer.ts b/src/controllers/se/installer.ts index c5a9f81..439bf2d 100644 --- a/src/controllers/se/installer.ts +++ b/src/controllers/se/installer.ts @@ -7,7 +7,7 @@ import { ContainerDef, DevDocker } from "./docker"; import Dockerode from "dockerode"; const DEFAULT_INSTANCE_NAME = "default"; -const DEFAULT_INSTANCE_PORT = 2020; +const DEFAULT_INSTANCE_PORT = 80; const DOCKER_IMAGE_NAME = "tonlabs/local-node"; const DOCKER_CONTAINER_NAME_PREFIX = "tonlabs-tonos-se"; @@ -27,7 +27,7 @@ type SEInstanceConfig = { * Port on localhost used to expose GraphQL API * GraphQL API is accessible through http://localhost:port/graphql * Node Requests API is accessible through http://localhost:port/topics/requests - * Default value: 2020 + * Default value: 80 */ port: number, /** @@ -100,20 +100,26 @@ export async function setConfig(config: SEConfig) { fs.writeFileSync(configPath(), JSON.stringify(config, undefined, " "), "utf8"); } -export function isInstanceMatched(instance: SEInstanceConfig, instanceFilter: string): boolean { - return instanceFilter === "*" || instanceFilter.toLowerCase() === instance.name.toLowerCase(); -} - -export async function filterInstances(instanceFilter: string): Promise { +export function filterInstances(instances: SEInstanceConfig[], filter: string): SEInstanceConfig[] { + const names = filter.toLowerCase().split(",").map(x => x.trim()).filter(x => x !== ""); + if (names.includes("*")) { + return instances; + } const filtered: SEInstanceConfig[] = []; - for (const instance of (await getConfig()).instances) { - if (isInstanceMatched(instance, instanceFilter)) { - filtered.push(instance); + names.forEach(name => { + const instance = instances.find(x => x.name.toLowerCase() === name); + if (instance === undefined) { + throw new Error(`Instance \"${name}\" is not found`); } - } + filtered.push(instance); + }); return filtered; } +export async function filterConfigInstances(filter: string): Promise { + return filterInstances(await (await getConfig()).instances, filter); +} + export function instanceContainerDef(instance: SEInstanceConfig): ContainerDef { const requiredImage = `${DOCKER_IMAGE_NAME}:${instance.version}`; const suffix = instance.name !== DEFAULT_INSTANCE_NAME ? `-${instance.name}` : ''; From 713dd212ae2288427e2f6f8a9025a40f83964da7 Mon Sep 17 00:00:00 2001 From: Michael Vlasov Date: Fri, 26 Feb 2021 17:34:43 +0500 Subject: [PATCH 20/24] NEW: preserve se instance state after config has updated --- src/controllers/se/commands.ts | 64 ++++++++------------------------- src/controllers/se/installer.ts | 43 +++++++++++++++++++--- 2 files changed, 54 insertions(+), 53 deletions(-) diff --git a/src/controllers/se/commands.ts b/src/controllers/se/commands.ts index 6ebded8..e315f76 100644 --- a/src/controllers/se/commands.ts +++ b/src/controllers/se/commands.ts @@ -1,12 +1,13 @@ import { filterConfigInstances, - filterInstances, getConfig, getInstanceInfo, getLatestVersion, getVersions, instanceContainerDef, - setConfig + PORT_NONE, + SEInstanceConfig, + updateConfig } from "./installer"; import { Command, CommandArg, Terminal } from "../../core"; import { ContainerDef, ContainerStatus, DevDocker } from "./docker"; @@ -109,16 +110,9 @@ export const seUpdateCommand: Command = { title: "Update SE Instance Version", args: [instanceArg], async run(terminal: Terminal, args: { instance: string }): Promise { - const config = await getConfig(); - const latestVersion = await getLatestVersion(); - const docker = new DevDocker(); - for (const instance of filterInstances(config.instances, args.instance)) { - instance.version = latestVersion; - const def = instanceContainerDef(instance); - await docker.shutdownContainer(terminal, def, ContainerStatus.missing); - await docker.startupContainer(terminal, def, ContainerStatus.created); - } - setConfig(config); + await updateConfig(terminal, args.instance, { + version: await getLatestVersion(), + }); }, }; @@ -153,63 +147,35 @@ export const seSetCommand: Command = { "db-port": string, instance: string }): Promise { - const config = await getConfig(); - const docker = new DevDocker(); - - let version: string | undefined = undefined; + const updates: Partial = {}; if (args.version !== "") { if (args.version.toLowerCase() === "latest") { - version = await getLatestVersion(); + updates.version = await getLatestVersion(); } else { if (!(await getVersions()).includes(args.version)) { throw new Error(`Invalid version: ${args.version}`); } - version = args.version; + updates.version = args.version; } } - let port: number | undefined = undefined; if (args.port !== "") { - port = Number.parseInt(args.port); - if (port === undefined) { + updates.port = Number.parseInt(args.port); + if (updates.port === undefined) { throw new Error(`Invalid port: ${args.port}`); } } - let dbPort: number | "none" | undefined = undefined; if (args["db-port"] !== "") { if (args["db-port"].toLowerCase() === "none") { - dbPort = "none"; + updates.dbPort = PORT_NONE; } else { - dbPort = Number.parseInt(args["db-port"]); - if (port === undefined) { + updates.dbPort = Number.parseInt(args["db-port"]); + if (updates.port === undefined) { throw new Error(`Invalid db-port: ${args["db-port"]}`); } } } - - const instances = filterInstances(config.instances, args.instance); - - if (version === undefined && port === undefined && dbPort === undefined) { - throw new Error("There is nothing to set. You have to specify at least one config parameter. See command help."); - } - - for (const instance of instances) { - if (version !== undefined) { - instance.version = version; - } - if (port !== undefined) { - instance.port = port; - } - if (dbPort === "none") { - delete instance.dbPort; - } else if (dbPort !== undefined) { - instance.dbPort = dbPort; - } - const def = instanceContainerDef(instance); - await docker.shutdownContainer(terminal, def, ContainerStatus.missing); - await docker.startupContainer(terminal, def, ContainerStatus.created); - } - setConfig(config); + await updateConfig(terminal, args.instance, updates); }, }; \ No newline at end of file diff --git a/src/controllers/se/installer.ts b/src/controllers/se/installer.ts index 439bf2d..d3a9dfa 100644 --- a/src/controllers/se/installer.ts +++ b/src/controllers/se/installer.ts @@ -1,20 +1,21 @@ import * as path from "path"; import * as fs from "fs"; -import { tondevHome } from "../../core"; +import { Terminal, tondevHome } from "../../core"; import { httpsGetJson, userIdentifier, versionToNumber } from "../../core/utils"; -import { ContainerDef, DevDocker } from "./docker"; +import { ContainerDef, ContainerStatus, DevDocker } from "./docker"; import Dockerode from "dockerode"; const DEFAULT_INSTANCE_NAME = "default"; const DEFAULT_INSTANCE_PORT = 80; const DOCKER_IMAGE_NAME = "tonlabs/local-node"; const DOCKER_CONTAINER_NAME_PREFIX = "tonlabs-tonos-se"; +export const PORT_NONE = -1; /** * SE instance config */ -type SEInstanceConfig = { +export type SEInstanceConfig = { /** * Instance name */ @@ -92,7 +93,7 @@ export async function getConfig(): Promise { return config; } -export async function setConfig(config: SEConfig) { +export function setConfig(config: SEConfig) { const configDir = path.dirname(configPath()); if (!fs.existsSync(configDir)) { fs.mkdirSync(configDir, { recursive: true }); @@ -181,3 +182,37 @@ export async function getInstanceInfo(docker: DevDocker, instance: SEInstanceCon }; } + +export async function updateConfig(terminal: Terminal, filter: string, updates: Partial): Promise { + const config = await getConfig(); + const docker = new DevDocker(); + + const instances = filterInstances(config.instances, filter); + + if (updates.version === undefined && updates.port === undefined && updates.dbPort === undefined) { + throw new Error("There is nothing to set. You have to specify at least one config parameter. See command help."); + } + + for (const instance of instances) { + if (updates.version !== undefined) { + instance.version = updates.version; + } + if (updates.port !== undefined) { + instance.port = updates.port; + } + if (updates.dbPort === PORT_NONE) { + delete instance.dbPort; + } else if (updates.dbPort !== undefined) { + instance.dbPort = updates.dbPort; + } + const def = instanceContainerDef(instance); + const info = await getInstanceInfo(docker, instance); + await docker.shutdownContainer(terminal, def, ContainerStatus.missing); + await docker.startupContainer( + terminal, + def, + info.state === "running" ? ContainerStatus.running : ContainerStatus.created, + ); + } + setConfig(config); +} From 123291ab42ad51687cf44788ad90d7f9680f0c6e Mon Sep 17 00:00:00 2001 From: elasticLove1 Date: Fri, 26 Feb 2021 17:08:19 +0300 Subject: [PATCH 21/24] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a150ad2..70d7d83 100644 --- a/README.md +++ b/README.md @@ -181,10 +181,11 @@ Available Versions: 0, 0.24, 0.24.5, 0.24.6, 0.24.8, 0.24.9, 0.24.10, 0.24.11, 0 ``` #### Set -This command switches tonon se to the specified version and downloads it, it is missing. +This command switches tonon se to the specified version and port and downloads it, it is missing. +Attention! This command does not start TON OS SE, you need to run `start` command separately. ```shell -tondev se set 0.24.11 +tondev se set --version 0.24.11 --port 2020 ``` #### Reset From 3e1cfbd647390747c1cabdc5afd81fec4e5cfb85 Mon Sep 17 00:00:00 2001 From: Ekaterina Pantaz <52739957+elasticLove1@users.noreply.github.com> Date: Fri, 26 Feb 2021 17:09:37 +0300 Subject: [PATCH 22/24] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 70d7d83..09e647b 100644 --- a/README.md +++ b/README.md @@ -181,8 +181,8 @@ Available Versions: 0, 0.24, 0.24.5, 0.24.6, 0.24.8, 0.24.9, 0.24.10, 0.24.11, 0 ``` #### Set -This command switches tonon se to the specified version and port and downloads it, it is missing. -Attention! This command does not start TON OS SE, you need to run `start` command separately. +This command switches TON OS SE to the specified version and port and downloads it, if it is missing. +**Attention! This command does not start TON OS SE, you need to run `start` command separately.** ```shell tondev se set --version 0.24.11 --port 2020 From 73275a5567fa46bce1a22738ef63e67b0d1d66e6 Mon Sep 17 00:00:00 2001 From: Ekaterina Pantaz <52739957+elasticLove1@users.noreply.github.com> Date: Fri, 26 Feb 2021 17:10:12 +0300 Subject: [PATCH 23/24] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 09e647b..42b4fea 100644 --- a/README.md +++ b/README.md @@ -181,7 +181,7 @@ Available Versions: 0, 0.24, 0.24.5, 0.24.6, 0.24.8, 0.24.9, 0.24.10, 0.24.11, 0 ``` #### Set -This command switches TON OS SE to the specified version and port and downloads it, if it is missing. +This command switches TON OS SE to the specified version and port and downloads it, if it is missing. **Attention! This command does not start TON OS SE, you need to run `start` command separately.** ```shell From 0b26b4c2e7b9bb6fd63a8d4ae08ac056acaaaf51 Mon Sep 17 00:00:00 2001 From: Sergei Voronezhskii Date: Fri, 26 Feb 2021 19:23:51 +0300 Subject: [PATCH 24/24] Github Action npm publish --- .github/workflows/npmpublish.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/workflows/npmpublish.yml diff --git a/.github/workflows/npmpublish.yml b/.github/workflows/npmpublish.yml new file mode 100644 index 0000000..fe79f55 --- /dev/null +++ b/.github/workflows/npmpublish.yml @@ -0,0 +1,18 @@ +name: npm publish + +on: + release: + types: [published] + +jobs: + publish-npm: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + with: + node-version: 12 + registry-url: https://registry.npmjs.org/ + - run: npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}