From 40e8f7c2934bd32bf85b659ae85b1662b706935e Mon Sep 17 00:00:00 2001 From: rpiontik Date: Fri, 2 Feb 2024 17:35:07 +0300 Subject: [PATCH 01/11] =?UTF-8?q?=D0=A0=D0=B0=D0=B7=D1=80=D0=B5=D0=B7?= =?UTF-8?q?=D0=B0=D0=BB=20=D0=BF=D0=BE=20=D0=B1=D0=B0=D0=B7=D0=BE=D0=B2?= =?UTF-8?q?=D1=8B=D0=BC=20=D0=BC=D0=BE=D0=B4=D1=83=D0=BB=D1=8F=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cli/log.js | 39 ++++ cli/main.js | 520 +----------------------------------------------- cli/packages.js | 394 ++++++++++++++++++++++++++++++++++++ cli/repo.js | 87 ++++++++ package.json | 2 +- 5 files changed, 524 insertions(+), 518 deletions(-) create mode 100644 cli/log.js mode change 100644 => 100755 cli/main.js create mode 100644 cli/packages.js create mode 100644 cli/repo.js diff --git a/cli/log.js b/cli/log.js new file mode 100644 index 0000000..9e5af46 --- /dev/null +++ b/cli/log.js @@ -0,0 +1,39 @@ + +module.exports = function () { + return { + level: 0, + begin(info) { + console.log(this.getMargin(), info); + this.level++; + }, + end(info) { + console.info(this.getMargin(), `\x1b[32m${info}\x1b[0m`); + this.level && this.level--; + }, + getMargin() { + return "||||||||||||||||||||||||||||||||||||||||||||||||||||||||".slice(0, this.level) + '-'; + }, + debug(info) { + console.log(this.getMargin(), info); + }, + error(info) { + console.error(this.getMargin(), `\x1b[31m${info}\x1b[0m`); + }, + success(info) { + console.info(this.getMargin(), `\x1b[32m${info}\x1b[0m`); + }, + progressBegin() { + }, + progress(value, total) { + if (total) { + const percentage = ((value * 100) / total).toFixed(2); + process.stdout.write(`\r${this.getMargin()} [${percentage}%] ${value} bytes out of ${total} bytes.`); + } else { + process.stdout.write(`\r${this.getMargin()} Recieved ${value} bytes.`); + } + }, + progressEnd() { + process.stdout.write('\r\n'); + }, + }; +} \ No newline at end of file diff --git a/cli/main.js b/cli/main.js old mode 100644 new mode 100755 index 96b7565..bdfa947 --- a/cli/main.js +++ b/cli/main.js @@ -3,532 +3,18 @@ // https://davidlozzi.com/2021/03/16/style-up-your-console-logs/ // Если часть пакетов поставилась, то их зависимости не разрешаются при установке - const request = require('request'); -// const unzipper = require('unzipper'); -const tar = require("tar"); -var zlib = require('zlib'); -const semver = require('semver'); -const fs = require('fs'); -const os = require('os'); const path = require('path'); -const SEP = path.sep; -const yaml = require('yaml'); -const REPO_SERVER = new URL(process.env.RACHPKG_REPO_SERVER || 'https://registry.dochub.info/'); const SSL_CERT = process.env.RACHPKG_SSL_CERT; const cwd = process.cwd(); const locationCWD = path.resolve(cwd, '_metamodel_'); -const importYamlName = 'packages.yaml'; - -const DEFAULT_DOCHUB_YAML = -` -$package: - ".": - version: 1.0.0 -`; - - -const log = { - level: 0, - begin(info) { - console.log(this.getMargin(), info); - this.level++; - }, - end(info) { - console.info(this.getMargin(), `\x1b[32m${info}\x1b[0m`); - this.level && this.level--; - }, - getMargin() { - return "||||||||||||||||||||||||||||||||||||||||||||||||||||||||".slice(0, this.level) + '-'; - }, - debug(info) { - console.log(this.getMargin(), info); - }, - error(info) { - console.error(this.getMargin(), `\x1b[31m${info}\x1b[0m`); - }, - success(info) { - console.info(this.getMargin(), `\x1b[32m${info}\x1b[0m`); - }, - progressBegin() { - }, - progress(value, total) { - if (total) { - const percentage = ((value * 100) / total).toFixed(2); - process.stdout.write(`\r${this.getMargin()} [${percentage}%] ${value} bytes out of ${total} bytes.`); - } else { - process.stdout.write(`\r${this.getMargin()} Recieved ${value} bytes.`); - } - }, - progressEnd() { - process.stdout.write('\r\n'); - }, -}; - - -const packageAPI = { - installed: {}, - tempFolders: [], - cacheFolder: null, - - beginInstall(params) { - this.installed = {}; - this.tempFolders = []; - this.cacheFolder = params.cacheFolder || path.resolve(os.homedir(), '.archpkg'); - log.debug(`Welcome to archpakg!`); - log.debug(`Using repo server [${REPO_SERVER}]`); - log.debug(`Cache forlder [${this.cacheFolder}]`); - if (params.cert) { - log.debug(`Will use sslcert [${params.cert}]`); - repoAPI.env.cert = fs.readFileSync(params.cert); - } - }, - - endInstall(isCleanCache = true) { - isCleanCache && this.cleanCache(); - }, - - cleanCache() { - log.begin('Clean cache...'); - fs.rmSync(this.getTempFolderFor(), { recursive: true, force: true }); - log.begin('Done.'); - }, - - // Добавляет импорт в файл - - // Строим граф зависимостей по данным из указанной области - async buildDependenciesGraph(location) { - log.begin('Building dependencies graph...'); - let result = []; - const tree = {}; - const installed = await this.fetchInstalledPackages(location); - // Инициализируем дерево зависимостей - installed.map((node) => { - for (const extId in node.metadata) { - const extention = node.metadata[extId]; - const out = Object.keys(extention.dependencies || {}); - !tree[extId] && (tree[extId] = { id: extId, in: [], out: [] }); - tree[extId].out = tree[extId].out.concat(out); - out.map((packageId) => { - !tree[packageId] && (tree[packageId] = { id: packageId, in: [], out: [] }); - tree[packageId].in.push(extId); - }); - } - }); - - // Разбираем дерево зависимостей - const pullNext = () => { - const result = []; - Object.keys(tree).map((packageId) => { - const package = tree[packageId]; - if (!package.in.length) { - package.out.map((outId) => { - tree[outId].in = tree[outId].in.filter((element) => element !== packageId); - }); - result.push(package); - delete tree[packageId]; - } - }); - return result; - }; - - let part = null; - while ((part = pullNext()).length) { - result = result.concat(part); - } - - const remainder = Object.keys(tree); - if (remainder.length > 0) - throw new Error(`Cyclic dependencies detected. Could not resolve dependencies for [${remainder.join(';')}]`); - - log.end('Done.'); - return result; - }, - - async makeImportsFileByDependenciesGraph(location, graph) { - const imports = []; - for (const i in graph) { - const item = graph[i]; - const source = await this.getSourceOfpackageId(location, item.id); - if (source) { - const packageFolder = path.basename(path.dirname((path.resolve(source, 'dochub.yaml')))); - imports.unshift(`${packageFolder}${path.sep}dochub.yaml`); - } - }; - return { - imports - }; - }, - - // Создает YAML файл подключения пакетов - async makeImportsYaml(location) { - log.begin('Building a packages import file...'); - const graph = await this.buildDependenciesGraph(location); - const imports = await packageAPI.makeImportsFileByDependenciesGraph(location, graph); - const dochubYaml = new yaml.Document(imports); - dochubYaml.commentBefore = 'This file is generated automatically by the utility https://www.npmjs.com/package/archpkg.\nIt is not recommended to make changes to it.'; - const filePath = path.resolve(location, importYamlName); - fs.writeFileSync(filePath, String(dochubYaml), { encoding: 'utf8', flag: 'w' }); - log.debug(`Built ${filePath}`); - log.end('Done.'); - return filePath; - }, - - // Добавляет зависимость в пакет - async addDependencyToDochubYaml(source, packageId, version, thisPackage) { - log.begin('Append dependency...'); - const content = fs.existsSync(source) - ? fs.readFileSync(source, { encoding: 'utf8' }) - : DEFAULT_DOCHUB_YAML; - const yamlFile = yaml.parseDocument(content); - const data = yamlFile.toJS() || {}; - if (!data.$package) { - thisPackage = thisPackage || '.'; - log.debug(`No $package entry found. It will be created with package id ${thisPackage}`); - data.$package = { [thisPackage]: { dependencies: {} } }; - yamlFile.add(yamlFile.createPair('$package', data.$package)); - } else if (!thisPackage) { - thisPackage = Object.keys(data.$package)[0]; - } - - const currentVersion = (data.$package[thisPackage].dependencies || {})[packageId]; - if (currentVersion !== version) { - const yaml$package = yamlFile.get('$package'); - const yamlPackageData = yaml$package.get(thisPackage); - let yamlDependencies = yamlPackageData.get('dependencies'); - if (!yamlDependencies) { - yamlPackageData.add(yamlFile.createPair('dependencies', {})); - yamlDependencies = yamlPackageData.get('dependencies'); - } - if (!currentVersion) { - yamlDependencies.add(yamlFile.createPair(packageId, version)); - } else { - yamlDependencies.set(packageId, version); - } - fs.writeFileSync(source, String(yamlFile), { encoding: 'utf8', flag: 'w' }); - } - - log.end('Done.'); - }, - - // Добавляет импорт в yaml - async addImportToDochubYaml(source, link) { - const content = fs.readFileSync(source, { encoding: 'utf8' }); - const yamlFile = yaml.parseDocument(content); - const data = yamlFile.toJS() || {}; - if ((data.imports || []).indexOf(link) < 0) { - const imports = yamlFile.get('imports'); - if (imports) { - imports.add(yamlFile.createNode(link)); - } else { - yamlFile.add(yamlFile.createPair('imports', [link])); - } - fs.writeFileSync(source, String(yamlFile), { encoding: 'utf8', flag: 'w' }); - } - }, - - getTempFolderFor(packageId) { - const result = packageId - ? path.resolve(this.cacheFolder, packageId) - : this.cacheFolder - packageId && this.tempFolders.push(result); - return result; - }, - - async downloadAndUnzipFrom(url, packageId) { - const tmpFolder = await this.getTempFolderFor(packageId); - return new Promise((success, reject) => { - // Если уже скачивали ранее и кэш сохранился используем его - if (fs.existsSync(tmpFolder)) { - log.begin(`Using cache [${tmpFolder}] for [${url}]`); - success(tmpFolder); - return; - } - // Создаем временную папку для скачивания - const tryFolder = `${tmpFolder}__`; - fs.existsSync(tryFolder) && fs.rmSync(tryFolder, { recursive: true }); - fs.mkdirSync(tryFolder, { recursive: true }); - log.begin(`Downloading ${url}...`); - let totalBytes = 0; - let receivedBytes = 0; - request(repoAPI.makeGetParams(url)) - .on('response', (data) => { - totalBytes = parseInt(data.headers['content-length']); - if (data.statusCode === 404) - reject(`Package unavailable on URL ${url}`); - if ((data.statusCode < 200) || data.statusCode > 300) - reject(`Error of downloading package from [${url}]. Response with code ${data.statusCode}.`); - log.progressBegin(); - }) - .on('data', (chunk) => { - receivedBytes += chunk.length; - log.progress(receivedBytes, totalBytes); - }) - .on('end', (chunk) => { - log.progressEnd(); - log.end('Done.'); - }) - .on('error', reject) - //.pipe(unzipper.Extract({ path: tmpFolder })) - .pipe(zlib.createGunzip()) - .pipe(tar.x({ - strip: 1, - C: tryFolder - })) - .on('error', reject) - .on('close', () => { - fs.renameSync(tryFolder, tmpFolder); - success(tmpFolder); - }); - }); - }, - - // Возвращает метаданные из указанного размещений - async getPackageMetadataFromSource(location) { - const manifest = path.resolve(location, 'dochub.yaml'); - if (!fs.existsSync(manifest)) - throw new Error(`Error of package structure. No found dochub.yaml in ${location}`); - const content = yaml.parse(fs.readFileSync(manifest, { encoding: 'utf8' })); - const result = content?.$package; - if (!result) - throw new Error(`No available $package metadata of package in ${manifest}`); - return result; - }, - - // Возвращает ссылку на ресурс, где встречается идентификатор пакета - async getSourceOfpackageId(location, packageId) { - const packages = await this.fetchInstalledPackages(location); - return (packages.find((package) => package.metadata[packageId]) || {}).source; - }, - - // Сканирует пространство на наличие пакетов и возвращает список директорий - async scanLocation(location) { - if (!fs.existsSync(location)) return []; - return fs.readdirSync(location, { withFileTypes: true }) - .filter(dirent => dirent.isDirectory()) - .map(dirent => dirent.name); - }, - - // Получает сведения об установленных пакетах в заданном пространстве - async fetchInstalledPackages(location) { - if (this.installed[location]) return this.installed[location]; - log.begin(`Fetch installed packages in ${location}...`); - const folders = await this.scanLocation(location); - const result = []; - for (const index in folders) { - log.debug(`Scanning ${folders[index]}`); - const source = path.resolve(location, folders[index]); - const metadata = await this.getPackageMetadataFromSource(source); - result.push( - { - source, - metadata - } - ); - } - log.end('Done.'); - return this.installed[location] = result; - }, - - async getPackageMetadata(location, packageId) { - const packages = await this.fetchInstalledPackages(location); - if (!packages) return null; - const package = packages.find((item) => { - return item.metadata[packageId]; - }); - return package ? { - source: package.source, - metadata: package.metadata[packageId] - } : null; - }, - - async getInstalledPackageVersion(location, packageId) { - const metadata = await this.getPackageMetadata(location, packageId); - return metadata ? metadata.metadata?.version : null; - }, - - async resolveDependencies(metadata, location) { - for (const extensionId in metadata) { - const dependencies = metadata[extensionId].dependencies; - if (dependencies) { - log.begin(`Install dependencies for [${extensionId}]...`); - for (const packageId in dependencies) { - const version = dependencies[packageId]; - await this.specificInstall(location, packageId, version); - } - log.end('Done.'); - } else log.debug(`Installed extension ${extensionId}`); - } - }, - - async installPackageTo(from, location, packageId) { - // const folder = (await this.scanLocation(from))[0]; - const folder = from; - if (!folder) - throw new Error(`Structure of the pecked is incorrect in ${from}!`); - !fs.existsSync(location) && fs.mkdirSync(location, { recursive: true }); - const source = path.resolve(from, folder); - const metadata = await this.getPackageMetadataFromSource(source) || {}; - // await this.resolveDependencies(metadata, location); - const destination = path.resolve(location, packageId); - fs.rmSync(destination, { recursive: true, force: true }); - fs.cpSync(source, destination, { recursive: true }); - /* - fs.renameSync(source, destination); - const toRemoveFolder = this.tempFolders.find((folder) => { - return source.startsWith(folder); - }); - toRemoveFolder && fs.rmSync(toRemoveFolder, { recursive: true, force: true }); - */ - (await this.fetchInstalledPackages(location)).push({ - source, - metadata - }); - - log.debug(`The package installed to ${destination}`); - return destination; - }, - - // Устанавливает все зависимости для конкретного пакета - async allInstall(location) { - log.begin(`installing dependencies...`); - const metadata = await packageAPI.getPackageMetadataFromSource(location) || {}; - await packageAPI.resolveDependencies(metadata, path.resolve(location, '_metamodel_')); - log.end(`Done.`); - }, - - // Устанавливает пакет в указанный location (например ./_metamodels_) - async specificInstall(location, packageId, packageVer) { - log.begin(`Try to install [${packageId}@${packageVer || 'latest'}]`); - let result = false; - const currentVer = await packageAPI.getInstalledPackageVersion(location, packageId); - - if ((currentVer && !packageVer) || semver.satisfies(currentVer, packageVer)) { - log.success(`Package ${packageId} already installed.`); - const metadata = await packageAPI.getPackageMetadataFromSource(path.resolve(location, packageId)) || {}; - await packageAPI.resolveDependencies(metadata, location); - result = currentVer; - } else { - const sourcePackage = await repoAPI.fetchSourceOfPackage(packageVer ? `${packageId}@${packageVer}` : packageId); - result = sourcePackage.version; - - if (sourcePackage.source !== 'built-in') { - const tempFolder = await packageAPI.downloadAndUnzipFrom(sourcePackage.source, packageId); - - if (currentVer) { - log.debug(`Current version ${currentVer} will be updated to ${packageVer}.`); - await this.removePackageFrom(location, packageId); - } - - await packageAPI.installPackageTo(tempFolder, location, packageId); - const metadata = await packageAPI.getPackageMetadataFromSource(path.resolve(location, packageId)) || {}; - await packageAPI.resolveDependencies(metadata, location); - } - } - - log.end(`Done.`); - return result; - }, - - - async removePackageFrom(location, packageId) { - log.begin(`Try to remove package ${packageId}...`); - const installed = await this.fetchInstalledPackages(location); - const package = await this.getPackageMetadata(location, packageId); - if (package) { - fs.rmSync(path.resolve(package.source), { recursive: true, force: true }); - const index = installed.findIndex((item) => item.source === package.source); - if (index >= 0) installed.splice(index, 1); - } else { - throw new Error(`Could not remove package ${packageId} from ${package.source} because it is not found.`); - } - log.end(`Done.`); - } -}; - -const doRequest = function (url) { - return new Promise(function (resolve, reject) { - try { - request(url, function (error, response, body) { - if (!error && (response.statusCode >= 200) && response.statusCode < 300) { - resolve({ - statusCode: response.statusCode, - response, - body - }); - } else { - reject(error || `Request to ${url} failed with code ${response.statusCode} and body [${body}]`); - } - }); - } catch (error) { - reject(error || `Request to ${url} failed.`); - } - }); -} - - -const repoAPI = { - env: { - token: null, // Токен авторизации - cert: null // Токен авторизации - }, - routes: { - access: { - guestToken: '/session/guest/token' - }, - repo: { - download: '/repo/download/' - } - }, - makeURL(route) { - return new URL(route, REPO_SERVER); - }, - makeGetParams(url) { - if (this.env.cert) { - return { - method: "GET", - uri: url, - agentOptions: { - ca: this.env.cert - } - }; - } else return url; - }, - async getAccess() { - if (!this.env.token) { - log.begin('Try to get access to repo...'); - const response = await doRequest( - this.makeURL(this.routes.access.guestToken).toString() - ); - const code = response && response.statusCode; - if (response && code !== 201) { - throw new Error(`Error server response with code ${code} and body [${response.body}]`); - } - const content = JSON.parse(response.body); - this.env.token = content.token; - log.end(`Access token provided: ${content.token}`); - } - }, - async fetchSourceOfPackage(package) { - await this.getAccess(); - const url = this.makeURL(`${this.routes.repo.download}${package}`).toString(); - log.begin(`Try to get link of package...`); - const response = await doRequest(url, { - auth: { - bearer: this.env.token - } - }); - if (response.statusCode !== 200) - throw new Error(`Error of resolve the download link of package ${package}. Response code ${response.statusCode} with body [${response.body}]`); - const content = JSON.parse(response.body); - log.end(`Link is found: ${content.source}`); - return content; - }, -}; +const log = require('./log')(); +const repoAPI = require('./repo')(log, request); +const packageAPI = require('./packages')(log, path, require('os'), require('fs'), repoAPI, request); const commands = { async remove(params) { diff --git a/cli/packages.js b/cli/packages.js new file mode 100644 index 0000000..781fb3d --- /dev/null +++ b/cli/packages.js @@ -0,0 +1,394 @@ +// Интерфейс работы с пакетами +// log - интерфейс для вывода логов +const yaml = require('yaml'); +const semver = require('semver'); +const zlib = require('zlib'); +const tar = require("tar"); + +const importYamlName = 'packages.yaml'; + +const DEFAULT_DOCHUB_YAML = +` +$package: + ".": + version: 1.0.0 +`; + +module.exports = function (log, path, os, fs, repoAPI, request) { + const SEP = path.sep; + + const packageAPI = { + installed: {}, + tempFolders: [], + cacheFolder: null, + + beginInstall(params) { + this.installed = {}; + this.tempFolders = []; + this.cacheFolder = params.cacheFolder || path.resolve(os.homedir(), '.archpkg'); + log.debug(`Welcome to archpakg!`); + log.debug(`Using repo server [${repoAPI.env.repoServer}]`); + log.debug(`Cache forlder [${this.cacheFolder}]`); + if (params.cert) { + log.debug(`Will use sslcert [${params.cert}]`); + repoAPI.env.cert = fs.readFileSync(params.cert); + } + }, + + endInstall(isCleanCache = true) { + isCleanCache && this.cleanCache(); + }, + + cleanCache() { + log.begin('Clean cache...'); + fs.rmSync(this.getTempFolderFor(), { recursive: true, force: true }); + log.begin('Done.'); + }, + + // Добавляет импорт в файл + + // Строим граф зависимостей по данным из указанной области + async buildDependenciesGraph(location) { + log.begin('Building dependencies graph...'); + let result = []; + const tree = {}; + const installed = await this.fetchInstalledPackages(location); + // Инициализируем дерево зависимостей + installed.map((node) => { + for (const extId in node.metadata) { + const extention = node.metadata[extId]; + const out = Object.keys(extention.dependencies || {}); + !tree[extId] && (tree[extId] = { id: extId, in: [], out: [] }); + tree[extId].out = tree[extId].out.concat(out); + out.map((packageId) => { + !tree[packageId] && (tree[packageId] = { id: packageId, in: [], out: [] }); + tree[packageId].in.push(extId); + }); + } + }); + + // Разбираем дерево зависимостей + const pullNext = () => { + const result = []; + Object.keys(tree).map((packageId) => { + const package_ = tree[packageId]; + if (!package_.in.length) { + package_.out.map((outId) => { + tree[outId].in = tree[outId].in.filter((element) => element !== packageId); + }); + result.push(package_); + delete tree[packageId]; + } + }); + return result; + }; + + let part = null; + while ((part = pullNext()).length) { + result = result.concat(part); + } + + const remainder = Object.keys(tree); + if (remainder.length > 0) + throw new Error(`Cyclic dependencies detected. Could not resolve dependencies for [${remainder.join(';')}]`); + + log.end('Done.'); + return result; + }, + + async makeImportsFileByDependenciesGraph(location, graph) { + const imports = []; + for (const i in graph) { + const item = graph[i]; + const source = await this.getSourceOfpackageId(location, item.id); + if (source) { + const packageFolder = path.basename(path.dirname((path.resolve(source, 'dochub.yaml')))); + imports.unshift(`${packageFolder}${path.sep}dochub.yaml`); + } + }; + return { + imports + }; + }, + + // Создает YAML файл подключения пакетов + async makeImportsYaml(location) { + log.begin('Building a packages import file...'); + const graph = await this.buildDependenciesGraph(location); + const imports = await packageAPI.makeImportsFileByDependenciesGraph(location, graph); + const dochubYaml = new yaml.Document(imports); + dochubYaml.commentBefore = 'This file is generated automatically by the utility https://www.npmjs.com/package/archpkg.\nIt is not recommended to make changes to it.'; + const filePath = path.resolve(location, importYamlName); + fs.writeFileSync(filePath, String(dochubYaml), { encoding: 'utf8', flag: 'w' }); + log.debug(`Built ${filePath}`); + log.end('Done.'); + return filePath; + }, + + // Добавляет зависимость в пакет + async addDependencyToDochubYaml(source, packageId, version, thisPackage) { + log.begin('Append dependency...'); + const content = fs.existsSync(source) + ? fs.readFileSync(source, { encoding: 'utf8' }) + : DEFAULT_DOCHUB_YAML; + const yamlFile = yaml.parseDocument(content); + const data = yamlFile.toJS() || {}; + if (!data.$package) { + thisPackage = thisPackage || '.'; + log.debug(`No $package entry found. It will be created with package id ${thisPackage}`); + data.$package = { [thisPackage]: { dependencies: {} } }; + yamlFile.add(yamlFile.createPair('$package', data.$package)); + } else if (!thisPackage) { + thisPackage = Object.keys(data.$package)[0]; + } + + const currentVersion = (data.$package[thisPackage].dependencies || {})[packageId]; + if (currentVersion !== version) { + const yaml$package = yamlFile.get('$package'); + const yamlPackageData = yaml$package.get(thisPackage); + let yamlDependencies = yamlPackageData.get('dependencies'); + if (!yamlDependencies) { + yamlPackageData.add(yamlFile.createPair('dependencies', {})); + yamlDependencies = yamlPackageData.get('dependencies'); + } + if (!currentVersion) { + yamlDependencies.add(yamlFile.createPair(packageId, version)); + } else { + yamlDependencies.set(packageId, version); + } + fs.writeFileSync(source, String(yamlFile), { encoding: 'utf8', flag: 'w' }); + } + + log.end('Done.'); + }, + + // Добавляет импорт в yaml + async addImportToDochubYaml(source, link) { + const content = fs.readFileSync(source, { encoding: 'utf8' }); + const yamlFile = yaml.parseDocument(content); + const data = yamlFile.toJS() || {}; + if ((data.imports || []).indexOf(link) < 0) { + const imports = yamlFile.get('imports'); + if (imports) { + imports.add(yamlFile.createNode(link)); + } else { + yamlFile.add(yamlFile.createPair('imports', [link])); + } + fs.writeFileSync(source, String(yamlFile), { encoding: 'utf8', flag: 'w' }); + } + }, + + getTempFolderFor(packageId) { + const result = packageId + ? path.resolve(this.cacheFolder, packageId) + : this.cacheFolder + packageId && this.tempFolders.push(result); + return result; + }, + + async downloadAndUnzipFrom(url, packageId) { + const tmpFolder = await this.getTempFolderFor(packageId); + return new Promise((success, reject) => { + // Если уже скачивали ранее и кэш сохранился используем его + if (fs.existsSync(tmpFolder)) { + log.begin(`Using cache [${tmpFolder}] for [${url}]`); + success(tmpFolder); + return; + } + // Создаем временную папку для скачивания + const tryFolder = `${tmpFolder}__`; + fs.existsSync(tryFolder) && fs.rmSync(tryFolder, { recursive: true }); + fs.mkdirSync(tryFolder, { recursive: true }); + + log.begin(`Downloading ${url}...`); + let totalBytes = 0; + let receivedBytes = 0; + request(repoAPI.makeGetParams(url)) + .on('response', (data) => { + totalBytes = parseInt(data.headers['content-length']); + if (data.statusCode === 404) + reject(`Package unavailable on URL ${url}`); + if ((data.statusCode < 200) || data.statusCode > 300) + reject(`Error of downloading package from [${url}]. Response with code ${data.statusCode}.`); + log.progressBegin(); + }) + .on('data', (chunk) => { + receivedBytes += chunk.length; + log.progress(receivedBytes, totalBytes); + }) + .on('end', (chunk) => { + log.progressEnd(); + log.end('Done.'); + }) + .on('error', reject) + //.pipe(unzipper.Extract({ path: tmpFolder })) + .pipe(zlib.createGunzip()) + .pipe(tar.x({ + strip: 1, + C: tryFolder + })) + .on('error', reject) + .on('close', () => { + fs.renameSync(tryFolder, tmpFolder); + success(tmpFolder); + }); + }); + }, + + // Возвращает метаданные из указанного размещений + async getPackageMetadataFromSource(location) { + const manifest = path.resolve(location, 'dochub.yaml'); + if (!fs.existsSync(manifest)) + throw new Error(`Error of package structure. No found dochub.yaml in ${location}`); + const content = yaml.parse(fs.readFileSync(manifest, { encoding: 'utf8' })); + const result = content?.$package; + if (!result) + throw new Error(`No available $package metadata of package in ${manifest}`); + return result; + }, + + // Возвращает ссылку на ресурс, где встречается идентификатор пакета + async getSourceOfpackageId(location, packageId) { + const packages = await this.fetchInstalledPackages(location); + return (packages.find((package_) => package_.metadata[packageId]) || {}).source; + }, + + // Сканирует пространство на наличие пакетов и возвращает список директорий + async scanLocation(location) { + if (!fs.existsSync(location)) return []; + return fs.readdirSync(location, { withFileTypes: true }) + .filter(dirent => dirent.isDirectory()) + .map(dirent => dirent.name); + }, + + // Получает сведения об установленных пакетах в заданном пространстве + async fetchInstalledPackages(location) { + if (this.installed[location]) return this.installed[location]; + log.begin(`Fetch installed packages in ${location}...`); + const folders = await this.scanLocation(location); + const result = []; + for (const index in folders) { + log.debug(`Scanning ${folders[index]}`); + const source = path.resolve(location, folders[index]); + const metadata = await this.getPackageMetadataFromSource(source); + result.push( + { + source, + metadata + } + ); + } + log.end('Done.'); + return this.installed[location] = result; + }, + + async getPackageMetadata(location, packageId) { + const packages = await this.fetchInstalledPackages(location); + if (!packages) return null; + const package_ = packages.find((item) => { + return item.metadata[packageId]; + }); + return package_ ? { + source: package_.source, + metadata: package_.metadata[packageId] + } : null; + }, + + async getInstalledPackageVersion(location, packageId) { + const metadata = await this.getPackageMetadata(location, packageId); + return metadata ? metadata.metadata?.version : null; + }, + + async resolveDependencies(metadata, location) { + for (const extensionId in metadata) { + const dependencies = metadata[extensionId].dependencies; + if (dependencies) { + log.begin(`Install dependencies for [${extensionId}]...`); + for (const packageId in dependencies) { + const version = dependencies[packageId]; + await this.specificInstall(location, packageId, version); + } + log.end('Done.'); + } else log.debug(`Installed extension ${extensionId}`); + } + }, + + async installPackageTo(from, location, packageId) { + // const folder = (await this.scanLocation(from))[0]; + const folder = from; + if (!folder) + throw new Error(`Structure of the pecked is incorrect in ${from}!`); + !fs.existsSync(location) && fs.mkdirSync(location, { recursive: true }); + const source = path.resolve(from, folder); + const metadata = await this.getPackageMetadataFromSource(source) || {}; + // await this.resolveDependencies(metadata, location); + const destination = path.resolve(location, packageId); + fs.rmSync(destination, { recursive: true, force: true }); + fs.cpSync(source, destination, { recursive: true }); + (await this.fetchInstalledPackages(location)).push({ + source, + metadata + }); + + log.debug(`The package installed to ${destination}`); + return destination; + }, + + // Устанавливает все зависимости для конкретного пакета + async allInstall(location) { + log.begin(`installing dependencies...`); + const metadata = await packageAPI.getPackageMetadataFromSource(location) || {}; + await packageAPI.resolveDependencies(metadata, path.resolve(location, '_metamodel_')); + log.end(`Done.`); + }, + + // Устанавливает пакет в указанный location (например ./_metamodels_) + async specificInstall(location, packageId, packageVer) { + log.begin(`Try to install [${packageId}@${packageVer || 'latest'}]`); + let result = false; + const currentVer = await packageAPI.getInstalledPackageVersion(location, packageId); + + if ((currentVer && !packageVer) || semver.satisfies(currentVer, packageVer)) { + log.success(`Package ${packageId} already installed.`); + const metadata = await packageAPI.getPackageMetadataFromSource(path.resolve(location, packageId)) || {}; + await packageAPI.resolveDependencies(metadata, location); + result = currentVer; + } else { + const sourcePackage = await repoAPI.fetchSourceOfPackage(packageVer ? `${packageId}@${packageVer}` : packageId); + result = sourcePackage.version; + + if (sourcePackage.source !== 'built-in') { + const tempFolder = await packageAPI.downloadAndUnzipFrom(sourcePackage.source, packageId); + + if (currentVer) { + log.debug(`Current version ${currentVer} will be updated to ${packageVer}.`); + await this.removePackageFrom(location, packageId); + } + + await packageAPI.installPackageTo(tempFolder, location, packageId); + const metadata = await packageAPI.getPackageMetadataFromSource(path.resolve(location, packageId)) || {}; + await packageAPI.resolveDependencies(metadata, location); + } + } + + log.end(`Done.`); + return result; + }, + + async removePackageFrom(location, packageId) { + log.begin(`Try to remove package ${packageId}...`); + const installed = await this.fetchInstalledPackages(location); + const package_ = await this.getPackageMetadata(location, packageId); + if (package_) { + fs.rmSync(path.resolve(package_.source), { recursive: true, force: true }); + const index = installed.findIndex((item) => item.source === package_.source); + if (index >= 0) installed.splice(index, 1); + } else { + throw new Error(`Could not remove package ${packageId} from ${package_.source} because it is not found.`); + } + log.end(`Done.`); + } + }; + + return packageAPI; +} \ No newline at end of file diff --git a/cli/repo.js b/cli/repo.js new file mode 100644 index 0000000..5475914 --- /dev/null +++ b/cli/repo.js @@ -0,0 +1,87 @@ + +const REPO_SERVER = new URL(process.env.RACHPKG_REPO_SERVER || 'https://registry.dochub.info/'); + +module.exports = function (log, request) { + const doRequest = function (url) { + return new Promise(function (resolve, reject) { + try { + request(url, function (error, response, body) { + if (!error && (response.statusCode >= 200) && response.statusCode < 300) { + resolve({ + statusCode: response.statusCode, + response, + body + }); + } else { + reject(error || `Request to ${url} failed with code ${response.statusCode} and body [${body}]`); + } + }); + } catch (error) { + reject(error || `Request to ${url} failed.`); + } + }); + } + + + const repoAPI = { + env: { + token: null, // Токен авторизации + cert: null, // Токен авторизации + repoServer: REPO_SERVER + }, + routes: { + access: { + guestToken: '/session/guest/token' + }, + repo: { + download: '/repo/download/' + } + }, + makeURL(route) { + return new URL(route, REPO_SERVER); + }, + makeGetParams(url) { + if (this.env.cert) { + return { + method: "GET", + uri: url, + agentOptions: { + ca: this.env.cert + } + }; + } else return url; + }, + async getAccess() { + if (!this.env.token) { + log.begin('Try to get access to repo...'); + const response = await doRequest( + this.makeURL(this.routes.access.guestToken).toString() + ); + const code = response && response.statusCode; + if (response && code !== 201) { + throw new Error(`Error server response with code ${code} and body [${response.body}]`); + } + const content = JSON.parse(response.body); + this.env.token = content.token; + log.end(`Access token provided: ${content.token}`); + } + }, + async fetchSourceOfPackage(package) { + await this.getAccess(); + const url = this.makeURL(`${this.routes.repo.download}${package}`).toString(); + log.begin(`Try to get link of package...`); + const response = await doRequest(url, { + auth: { + bearer: this.env.token + } + }); + if (response.statusCode !== 200) + throw new Error(`Error of resolve the download link of package ${package}. Response code ${response.statusCode} with body [${response.body}]`); + const content = JSON.parse(response.body); + log.end(`Link is found: ${content.source}`); + return content; + }, + }; + + return repoAPI; +} \ No newline at end of file diff --git a/package.json b/package.json index 3f46e5e..67e81bc 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "DocHub", "AaaC", "Metamodels", - "Achitecture" + "Architecture" ], "author": "R.Piontik", "license": "GPLV3", From 8c141fda0130d730eb3ee5b85f2f18c83b1bbae3 Mon Sep 17 00:00:00 2001 From: rpiontik Date: Sun, 4 Feb 2024 11:59:05 +0300 Subject: [PATCH 02/11] =?UTF-8?q?=D0=92=D1=8B=D0=B4=D0=B5=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=BC=D0=BE=D0=B4=D1=83=D0=BB=D1=8C=20=D1=81=D0=BA?= =?UTF-8?q?=D0=B0=D1=87=D0=B8=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=BF=D0=B0?= =?UTF-8?q?=D0=BA=D0=B5=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 ++++ cli/downloader.js | 65 ++++++++++++++++++++++++++++++++++++++++++ cli/main.js | 72 ++++++++++++++++++++++++++++++++++++----------- cli/packages.js | 65 +++++++++--------------------------------- cli/repo.js | 16 +++-------- 5 files changed, 142 insertions(+), 81 deletions(-) create mode 100644 cli/downloader.js diff --git a/README.md b/README.md index f6e08b4..247b8f6 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,11 @@ npx archpkg remove dochub-examples npx archpkg clean ``` +# Переменные среды + +* **ARCHPKG_CACHE_FOLDER** - путь к директории кэширования. По умолчанию: <ползовательская директория>/.archpkg +* **ARCHPKG_REPO_SERVER** - сервер репозитория. По умолчанию: https://registry.dochub.info/ +* **ARCHPKG_DOWNLOAD_CERT** - пусть к ssl-сертификату для скачивания пакетов. По умолчанию не установлено. # Лицензия diff --git a/cli/downloader.js b/cli/downloader.js new file mode 100644 index 0000000..528a312 --- /dev/null +++ b/cli/downloader.js @@ -0,0 +1,65 @@ +const zlib = require('zlib'); +const tar = require("tar"); + +// Реализует функцию загрузки и распаковки пакетов +module.exports = function (context) { + const fs = context.fs; + const log = context.log; + + return { + makeDownloadParams(url, method = 'GET') { + if (context.env.downloadCert) { + return { + method, + url, + agentOptions: { + ca: context.env.downloadCert + } + }; + } else return url; + }, + + async downloadAndUnzip(url, tmpFolder) { + return new Promise((success, reject) => { + // Создаем временную папку для скачивания + const tryFolder = `${tmpFolder}__`; + fs.existsSync(tryFolder) && fs.rmSync(tryFolder, { recursive: true }); + fs.mkdirSync(tryFolder, { recursive: true }); + + log.begin(`Downloading ${url}...`); + let totalBytes = 0; + let receivedBytes = 0; + + context.request(this.makeDownloadParams(url)) + .on('response', (data) => { + totalBytes = parseInt(data.headers['content-length']); + if (data.statusCode === 404) + reject(`Package unavailable on URL ${url}`); + if ((data.statusCode < 200) || data.statusCode > 300) + reject(`Error of downloading package from [${url}]. Response with code ${data.statusCode}.`); + log.progressBegin(); + }) + .on('data', (chunk) => { + receivedBytes += chunk.length; + log.progress(receivedBytes, totalBytes); + }) + .on('end', (chunk) => { + log.progressEnd(); + log.end('Done.'); + }) + .on('error', reject) + //.pipe(unzipper.Extract({ path: tmpFolder })) + .pipe(zlib.createGunzip()) + .pipe(tar.x({ + strip: 1, + C: tryFolder + })) + .on('error', reject) + .on('close', () => { + fs.renameSync(tryFolder, tmpFolder); + success(tmpFolder); + }); + }); + } + } +} \ No newline at end of file diff --git a/cli/main.js b/cli/main.js index bdfa947..c6c20a5 100755 --- a/cli/main.js +++ b/cli/main.js @@ -3,9 +3,10 @@ // https://davidlozzi.com/2021/03/16/style-up-your-console-logs/ // Если часть пакетов поставилась, то их зависимости не разрешаются при установке -const request = require('request'); - const path = require('path'); +const fs = require('fs'); +const os = require('os'); + const SSL_CERT = process.env.RACHPKG_SSL_CERT; @@ -13,8 +14,30 @@ const cwd = process.cwd(); const locationCWD = path.resolve(cwd, '_metamodel_'); const log = require('./log')(); -const repoAPI = require('./repo')(log, request); -const packageAPI = require('./packages')(log, path, require('os'), require('fs'), repoAPI, request); + +// Формируем контекст работы пакетного менеджера +const context = { + env : { // Перемнные среды для archpkg + cacheFolder: // Пространство для создания кэшей + process.env.ARCHPKG_CACHE_FOLDER + || path.resolve(os.homedir(), '.archpkg'), + repoServer: new URL( // Адрес сервера индекса пакетов + process.env.ARCHPKG_REPO_SERVER || 'https://registry.dochub.info/' + ), + downloadCert: // Ссылка на SSL сертификат для скачивания + process.env.ARCHPKG_DOWNLOAD_CERT || null + }, + request: require('request'), // Реализация запросов web-запросов + log: require('./log')(), // Реализация системы логирования + path, // Работа с путями + fs, // Функции файловой системы + downloader: null, // Функции загрузки пакетов + repo: null, // Функции archpkg репозитория + manager: null // Функции пакетного менеджера +}; +context.downloader = require('./downloader')(context); +context.repo = require('./repo')(context); +context.manager = require('./packages')(context); const commands = { async remove(params) { @@ -22,36 +45,35 @@ const commands = { if (!package) throw new Error('Package name is required!'); const packageStruct = package.split('@'); const packageId = packageStruct[0]; - await packageAPI.removePackageFrom(locationCWD, packageId); + await context.manager.removePackageFrom(locationCWD, packageId); }, async install(params) { const package = params[0]; if (!package) { - await packageAPI.allInstall(cwd); + await context.manager.allInstall(cwd); } else { const packageStruct = package.split('@'); const packageId = packageStruct[0]; let packageVer = packageStruct[1]; - packageVer = await packageAPI.specificInstall(path.resolve(cwd, '_metamodel_'), packageId, packageVer); + packageVer = await context.manager.specificInstall(path.resolve(cwd, '_metamodel_'), packageId, packageVer); packageVer && commandFlags.save - && await packageAPI.addDependencyToDochubYaml( + && await context.manager.addDependencyToDochubYaml( path.resolve(cwd, 'dochub.yaml'), packageId, packageVer ); } - const packagesYaml = await packageAPI.makeImportsYaml(locationCWD); + const packagesYaml = await context.manager.makeImportsYaml(locationCWD); if (commandFlags.save) { - await packageAPI.addImportToDochubYaml(path.resolve(cwd, 'dochub.yaml'), `_metamodel_${path.sep}packages.yaml`); + await context.manager.addImportToDochubYaml(path.resolve(cwd, 'dochub.yaml'), `_metamodel_${path.sep}packages.yaml`); } else { log.success(`\nSuccess!\n\nIMPORTANT: You need to manually specify the import of the ${packagesYaml} file for your project.\nIf you want to add imports automatically, use the "-save" option.\n`); } }, async clean() { - packageAPI.cleanCache(); - + context.manager.cleanCache(); } }; @@ -63,8 +85,13 @@ const commandFlags = { }; const run = async () => { + context.log.debug(`Welcome to archpakg!`); + log.debug(`Using repo server [${context.env.repoServer}]`); + log.debug(`Cache forlder [${context.env.cacheFolder}]`); + const params = []; + // Разбираем параметры запуска process.argv.map((arg) => { const struct = arg.split(':'); let key = struct[0].toLocaleLowerCase(); @@ -80,10 +107,21 @@ const run = async () => { } }); - packageAPI.beginInstall({ - cacheFolder: commandFlags.cachefolder, - cert: commandFlags.downloadcert - }); + // Если явно указана папка кэширования, устанавливаем ее + context.env.cacheFolder = commandFlags.cachefolder || context.env.cacheFolder; + + // Если указан сертификат для скачивания, устанавливаем его + context.env.downloadCert = commandFlags.downloadcert || context.env.downloadCert; + + // Если используется собственный сертификат для скачивания - загружаем + if (context.env.downloadCert) { + context.log.debug(`Will use sslcert [${context.env.downloadCert}]`); + // Загружаем сертификат + context.env.downloadCert = context.fs.readFileSync(context.env.downloadCert); + } + + // Запускаем установку + context.manager.beginInstall(); const command = params[2]; const handler = commands[params[2] || '$undefined$']; @@ -102,4 +140,4 @@ run() log.error(error) process.exit(1) }) - .finally(() => packageAPI.endInstall(commandFlags.cleancache)); + .finally(() => context.manager.endInstall(commandFlags.cleancache)); diff --git a/cli/packages.js b/cli/packages.js index 781fb3d..12a3900 100644 --- a/cli/packages.js +++ b/cli/packages.js @@ -2,8 +2,6 @@ // log - интерфейс для вывода логов const yaml = require('yaml'); const semver = require('semver'); -const zlib = require('zlib'); -const tar = require("tar"); const importYamlName = 'packages.yaml'; @@ -14,25 +12,24 @@ $package: version: 1.0.0 `; -module.exports = function (log, path, os, fs, repoAPI, request) { +module.exports = function (context) { + const log = context.log; + const path = context.path; + const os = context.os; + const fs = context.fs; + const repoAPI = context.repo; + const request = context.request; + const SEP = path.sep; const packageAPI = { installed: {}, tempFolders: [], - cacheFolder: null, + cacheFolder: context.env.cacheFolder, - beginInstall(params) { + beginInstall() { this.installed = {}; this.tempFolders = []; - this.cacheFolder = params.cacheFolder || path.resolve(os.homedir(), '.archpkg'); - log.debug(`Welcome to archpakg!`); - log.debug(`Using repo server [${repoAPI.env.repoServer}]`); - log.debug(`Cache forlder [${this.cacheFolder}]`); - if (params.cert) { - log.debug(`Will use sslcert [${params.cert}]`); - repoAPI.env.cert = fs.readFileSync(params.cert); - } }, endInstall(isCleanCache = true) { @@ -45,8 +42,6 @@ module.exports = function (log, path, os, fs, repoAPI, request) { log.begin('Done.'); }, - // Добавляет импорт в файл - // Строим граф зависимостей по данным из указанной области async buildDependenciesGraph(location) { log.begin('Building dependencies graph...'); @@ -195,43 +190,9 @@ module.exports = function (log, path, os, fs, repoAPI, request) { success(tmpFolder); return; } - // Создаем временную папку для скачивания - const tryFolder = `${tmpFolder}__`; - fs.existsSync(tryFolder) && fs.rmSync(tryFolder, { recursive: true }); - fs.mkdirSync(tryFolder, { recursive: true }); - - log.begin(`Downloading ${url}...`); - let totalBytes = 0; - let receivedBytes = 0; - request(repoAPI.makeGetParams(url)) - .on('response', (data) => { - totalBytes = parseInt(data.headers['content-length']); - if (data.statusCode === 404) - reject(`Package unavailable on URL ${url}`); - if ((data.statusCode < 200) || data.statusCode > 300) - reject(`Error of downloading package from [${url}]. Response with code ${data.statusCode}.`); - log.progressBegin(); - }) - .on('data', (chunk) => { - receivedBytes += chunk.length; - log.progress(receivedBytes, totalBytes); - }) - .on('end', (chunk) => { - log.progressEnd(); - log.end('Done.'); - }) - .on('error', reject) - //.pipe(unzipper.Extract({ path: tmpFolder })) - .pipe(zlib.createGunzip()) - .pipe(tar.x({ - strip: 1, - C: tryFolder - })) - .on('error', reject) - .on('close', () => { - fs.renameSync(tryFolder, tmpFolder); - success(tmpFolder); - }); + context.downloader.downloadAndUnzip(url, tmpFolder) + .then(success) + .catch(reject) }); }, diff --git a/cli/repo.js b/cli/repo.js index 5475914..a429131 100644 --- a/cli/repo.js +++ b/cli/repo.js @@ -1,7 +1,10 @@ const REPO_SERVER = new URL(process.env.RACHPKG_REPO_SERVER || 'https://registry.dochub.info/'); -module.exports = function (log, request) { +module.exports = function (context) { + const log = context.log; + const request = context.request; + const doRequest = function (url) { return new Promise(function (resolve, reject) { try { @@ -40,17 +43,6 @@ module.exports = function (log, request) { makeURL(route) { return new URL(route, REPO_SERVER); }, - makeGetParams(url) { - if (this.env.cert) { - return { - method: "GET", - uri: url, - agentOptions: { - ca: this.env.cert - } - }; - } else return url; - }, async getAccess() { if (!this.env.token) { log.begin('Try to get access to repo...'); From bdabf2130b7055d55cd322a516e33220f3275268 Mon Sep 17 00:00:00 2001 From: rpiontik Date: Sun, 10 Mar 2024 14:02:39 +0300 Subject: [PATCH 03/11] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D1=8C=20=D1=81=20=D0=BA=D0=BB=D0=B8=D0=B5=D0=BD?= =?UTF-8?q?=D1=82=D0=B0=20=D0=BD=D0=B0=D1=85=D0=BE=D0=B4=D0=B8=D1=82=D1=8C?= =?UTF-8?q?=20=D0=BE=D0=BF=D1=82=D0=B8=D0=BC=D0=B0=D0=BB=D1=8C=D0=BD=D1=83?= =?UTF-8?q?=D1=8E=20=D0=B2=D0=B5=D1=80=D1=81=D0=B8=D1=8E=20=D0=BF=D0=B0?= =?UTF-8?q?=D0=BA=D0=B5=D1=82=D0=B0=20=D0=BD=D0=B0=20github?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cli/main.js | 18 ++++++------- cli/repo.js | 78 ++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 73 insertions(+), 23 deletions(-) diff --git a/cli/main.js b/cli/main.js index c6c20a5..811fb3e 100755 --- a/cli/main.js +++ b/cli/main.js @@ -1,15 +1,11 @@ #!/usr/bin/env node // https://davidlozzi.com/2021/03/16/style-up-your-console-logs/ -// Если часть пакетов поставилась, то их зависимости не разрешаются при установке const path = require('path'); const fs = require('fs'); const os = require('os'); - -const SSL_CERT = process.env.RACHPKG_SSL_CERT; - const cwd = process.cwd(); const locationCWD = path.resolve(cwd, '_metamodel_'); @@ -18,7 +14,7 @@ const log = require('./log')(); // Формируем контекст работы пакетного менеджера const context = { env : { // Перемнные среды для archpkg - cacheFolder: // Пространство для создания кэшей + cacheFolder: // Директория для создания кэшей process.env.ARCHPKG_CACHE_FOLDER || path.resolve(os.homedir(), '.archpkg'), repoServer: new URL( // Адрес сервера индекса пакетов @@ -27,7 +23,7 @@ const context = { downloadCert: // Ссылка на SSL сертификат для скачивания process.env.ARCHPKG_DOWNLOAD_CERT || null }, - request: require('request'), // Реализация запросов web-запросов + request: require('request'), // Реализация web-запросов log: require('./log')(), // Реализация системы логирования path, // Работа с путями fs, // Функции файловой системы @@ -35,6 +31,7 @@ const context = { repo: null, // Функции archpkg репозитория manager: null // Функции пакетного менеджера }; + context.downloader = require('./downloader')(context); context.repo = require('./repo')(context); context.manager = require('./packages')(context); @@ -77,11 +74,12 @@ const commands = { } }; +// Параметры командной строки const commandFlags = { - cleancache: false, // Признак очистки кэша после установки - save: false, // Признак необходимости автоматически подключить пакеты в dochub.yaml - cachefolder: null, // Корневой путь к кэшу - downloadcert: SSL_CERT || null // Сертификат для скачивания + cleancache: false, // Признак очистки кэша после установки + save: false, // Признак необходимости автоматически подключить пакеты в dochub.yaml + cachefolder: null, // Корневой путь к кэшу + downloadcert: null // Сертификат для скачивания }; const run = async () => { diff --git a/cli/repo.js b/cli/repo.js index a429131..ebad999 100644 --- a/cli/repo.js +++ b/cli/repo.js @@ -1,14 +1,12 @@ - -const REPO_SERVER = new URL(process.env.RACHPKG_REPO_SERVER || 'https://registry.dochub.info/'); +const semver = require('semver'); module.exports = function (context) { const log = context.log; - const request = context.request; const doRequest = function (url) { return new Promise(function (resolve, reject) { try { - request(url, function (error, response, body) { + context.request(url, function (error, response, body) { if (!error && (response.statusCode >= 200) && response.statusCode < 300) { resolve({ statusCode: response.statusCode, @@ -25,23 +23,21 @@ module.exports = function (context) { }); } - - const repoAPI = { + return { env: { - token: null, // Токен авторизации - cert: null, // Токен авторизации - repoServer: REPO_SERVER + token: null // Токен авторизации }, routes: { access: { guestToken: '/session/guest/token' }, repo: { - download: '/repo/download/' + download: '/repo/download/', + metadata: '/repo/metadata/' } }, makeURL(route) { - return new URL(route, REPO_SERVER); + return new URL(route, context.env.repoServer); }, async getAccess() { if (!this.env.token) { @@ -58,7 +54,64 @@ module.exports = function (context) { log.end(`Access token provided: ${content.token}`); } }, + async fetchReleasesByOwnerRepoVer(owner, repo, version) { + const fetchURL = this.makeURL(`https://api.github.com/repos/${owner}/${repo}/releases`).toString(); + log.begin(`Try to get fetch releases from ${fetchURL} for version [${version ? version : 'any'}]...`); + const response = await doRequest({ + url: fetchURL, + headers: { + 'User-Agent': 'archpkg', + 'Accept': 'application/vnd.github+json', + 'X-GitHub-Api-Version': '2022-11-28' + } + }); + const content = JSON.parse(response.body); + const versions = content.filter((item) => { + return !version || semver.satisfies(item.tag_name, version) || semver.satisfies(item.tag_name.slice(1), version); + }).sort((v1, v2) => { + const strvToNumber = function (rel) { + const struct = rel.tag_name.toString().replace('v', '').split('.'); + const result = + Number.parseInt(struct[0] || '0') * 1000000000 + + Number.parseInt(struct[1] || '0') * 1000000 + + Number.parseInt(struct[2] || '0') * 1000; + return result; + }; + return strvToNumber(v1) - strvToNumber(v2); + }); + log.end(`Found versions: ${versions.map(item => item.tag_name).join(', ')}.`); + return versions; + }, async fetchSourceOfPackage(package) { + await this.getAccess(); + const url = this.makeURL(`${this.routes.repo.metadata}${package}`).toString(); + log.begin(`Try to get link of package [${package}]...`); + const response = await doRequest(url, { + auth: { + bearer: this.env.token + } + }); + if (response.statusCode !== 200) + throw new Error(`Error of resolve the download link of package ${package}. Response code ${response.statusCode} with body [${response.body}]`); + const content = JSON.parse(response.body); + if (content.repo === '$built-in$') { + log.end(`The package is built-in.`); + return { + source: 'built-in' + } + } + log.debug(`Owner: ${content.owner}, Repo: ${content.repo}`); + const releases = await this.fetchReleasesByOwnerRepoVer(content.owner, content.repo, package.split('@')[1]); + if (!releases || !releases.length) + throw new Error(`No found any release for ${$package}!`); + const release = releases.pop(); + const result = { + 'source': `https://codeload.github.com/${content.owner}/${content.repo}/tar.gz/refs/tags/${release.tag_name}` + }; + log.end(`Link is found: ${result.source}`); + return result; + }, + async fetchSourceOfPackage_(package) { await this.getAccess(); const url = this.makeURL(`${this.routes.repo.download}${package}`).toString(); log.begin(`Try to get link of package...`); @@ -71,9 +124,8 @@ module.exports = function (context) { throw new Error(`Error of resolve the download link of package ${package}. Response code ${response.statusCode} with body [${response.body}]`); const content = JSON.parse(response.body); log.end(`Link is found: ${content.source}`); + process.exit(0); return content; }, }; - - return repoAPI; } \ No newline at end of file From 4ddb698928f06cea9a277f1ed69b14def696e115 Mon Sep 17 00:00:00 2001 From: rpiontik Date: Mon, 11 Mar 2024 11:02:01 +0300 Subject: [PATCH 04/11] =?UTF-8?q?=D0=A3=D1=81=D1=82=D1=80=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D1=83=20=D1=83?= =?UTF-8?q?=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BF=D0=B0=D0=BA?= =?UTF-8?q?=D0=B5=D1=82=D0=BE=D0=B2=20=D0=B8=D0=B7=20=D0=BA=D1=8D=D1=88?= =?UTF-8?q?=D0=B0=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B4=20=D1=83=D1=81=D1=82?= =?UTF-8?q?=D0=B0=D0=BD=D0=BE=D0=B2=D0=BA=D0=BE=D0=B9.=20=D0=94=D0=BE?= =?UTF-8?q?=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=BA=D0=BE=D0=BD=D1=82=D1=80?= =?UTF-8?q?=D0=BE=D0=BB=D1=8C=20=D0=BF=D1=80=D0=BE=D1=82=D0=B8=D0=B2=D0=BE?= =?UTF-8?q?=D1=80=D0=B5=D1=87=D0=B8=D0=B9=20=D0=B7=D0=B0=D0=B2=D0=B8=D1=81?= =?UTF-8?q?=D0=B8=D0=BC=D0=BE=D1=81=D1=82=D0=B5=D0=B9.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cli/packages.js | 26 +++++++++++++++++++++++--- cli/repo.js | 17 +---------------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/cli/packages.js b/cli/packages.js index 12a3900..c8733a5 100644 --- a/cli/packages.js +++ b/cli/packages.js @@ -295,7 +295,7 @@ module.exports = function (context) { return destination; }, - // Устанавливает все зависимости для конкретного пакета + // Устанавливает все зависимости для конкретного пакетаsem async allInstall(location) { log.begin(`installing dependencies...`); const metadata = await packageAPI.getPackageMetadataFromSource(location) || {}; @@ -303,6 +303,22 @@ module.exports = function (context) { log.end(`Done.`); }, + // Проверяем можно ли обновить пакет к указанной версии + async isAvailableToUpdate(packageId, toVersion) { + const result = []; + for(const location in this.installed) { + this.installed[location].map((package) => { + for (const pkgID in package.metadata || {}) { + const metadata = package.metadata[pkgID]; + const reqVer = (metadata.dependencies || {})[packageId]; + if (reqVer && !semver.satisfies(toVersion, reqVer) ) { + result.push(`Conflict version of dependencies. For ${packageId} required ${toVersion} version, but packege ${pkgID} required ${reqVer} version.`); + } + } + }); + } + return result.length ? result : null; + }, // Устанавливает пакет в указанный location (например ./_metamodels_) async specificInstall(location, packageId, packageVer) { log.begin(`Try to install [${packageId}@${packageVer || 'latest'}]`); @@ -319,13 +335,17 @@ module.exports = function (context) { result = sourcePackage.version; if (sourcePackage.source !== 'built-in') { - const tempFolder = await packageAPI.downloadAndUnzipFrom(sourcePackage.source, packageId); - if (currentVer) { + const conflicts = await this.isAvailableToUpdate(packageId, packageVer); + if (conflicts) { + conflicts.map(message => log.error(message)); + throw new Error('Can not resolve dependencies!'); + } log.debug(`Current version ${currentVer} will be updated to ${packageVer}.`); await this.removePackageFrom(location, packageId); } + const tempFolder = await packageAPI.downloadAndUnzipFrom(sourcePackage.source, packageId); await packageAPI.installPackageTo(tempFolder, location, packageId); const metadata = await packageAPI.getPackageMetadataFromSource(path.resolve(location, packageId)) || {}; await packageAPI.resolveDependencies(metadata, location); diff --git a/cli/repo.js b/cli/repo.js index ebad999..2ca7a16 100644 --- a/cli/repo.js +++ b/cli/repo.js @@ -106,26 +106,11 @@ module.exports = function (context) { throw new Error(`No found any release for ${$package}!`); const release = releases.pop(); const result = { + package, 'source': `https://codeload.github.com/${content.owner}/${content.repo}/tar.gz/refs/tags/${release.tag_name}` }; log.end(`Link is found: ${result.source}`); return result; }, - async fetchSourceOfPackage_(package) { - await this.getAccess(); - const url = this.makeURL(`${this.routes.repo.download}${package}`).toString(); - log.begin(`Try to get link of package...`); - const response = await doRequest(url, { - auth: { - bearer: this.env.token - } - }); - if (response.statusCode !== 200) - throw new Error(`Error of resolve the download link of package ${package}. Response code ${response.statusCode} with body [${response.body}]`); - const content = JSON.parse(response.body); - log.end(`Link is found: ${content.source}`); - process.exit(0); - return content; - }, }; } \ No newline at end of file From 309efd1741dc60182d4a06cde9ab433c40ece0cc Mon Sep 17 00:00:00 2001 From: rpiontik Date: Mon, 11 Mar 2024 15:17:26 +0300 Subject: [PATCH 05/11] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D1=8C=20=D1=81=D0=BA=D0=B0=D1=87=D0=B8=D0=B2?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=BF=D0=B0=D0=BA=D0=B5=D1=82=D0=BE?= =?UTF-8?q?=D0=B2=20=D0=BF=D0=BE=20=D0=BF=D1=80=D1=8F=D0=BC=D1=8B=D0=BC=20?= =?UTF-8?q?=D1=81=D1=81=D1=8B=D0=BB=D0=BA=D0=B0=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cli/repo.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/cli/repo.js b/cli/repo.js index 2ca7a16..7a4f873 100644 --- a/cli/repo.js +++ b/cli/repo.js @@ -100,15 +100,21 @@ module.exports = function (context) { source: 'built-in' } } - log.debug(`Owner: ${content.owner}, Repo: ${content.repo}`); - const releases = await this.fetchReleasesByOwnerRepoVer(content.owner, content.repo, package.split('@')[1]); - if (!releases || !releases.length) - throw new Error(`No found any release for ${$package}!`); - const release = releases.pop(); const result = { - package, - 'source': `https://codeload.github.com/${content.owner}/${content.repo}/tar.gz/refs/tags/${release.tag_name}` + package }; + + if (content.type==='github') { + log.debug(`GitHub location Owner: ${content.owner}, Repo: ${content.repo}`); + const releases = await this.fetchReleasesByOwnerRepoVer(content.owner, content.repo, package.split('@')[1]); + if (!releases || !releases.length) + throw new Error(`No found any release for ${$package}!`); + const release = releases.pop(); + result.source = `https://codeload.github.com/${content.owner}/${content.repo}/tar.gz/refs/tags/${release.tag_name}` + } else if (content.type==='direct') { + log.debug('Direct location'); + result.source = content.source; + } log.end(`Link is found: ${result.source}`); return result; }, From e8d1ed00bc1ff5a2ac1ff173fea69a0a7f77e055 Mon Sep 17 00:00:00 2001 From: rpiontik Date: Wed, 13 Mar 2024 17:38:10 +0300 Subject: [PATCH 06/11] =?UTF-8?q?=D0=A3=D1=81=D1=82=D1=80=D0=B0=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B0=20?= =?UTF-8?q?=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20?= =?UTF-8?q?=D0=BF=D0=B0=D0=BA=D0=B5=D1=82=D0=B0=20=D0=BF=D1=80=D0=B8=20?= =?UTF-8?q?=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D0=B8=20=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D1=81=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cli/packages.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/cli/packages.js b/cli/packages.js index c8733a5..915131b 100644 --- a/cli/packages.js +++ b/cli/packages.js @@ -24,24 +24,28 @@ module.exports = function (context) { const packageAPI = { installed: {}, - tempFolders: [], cacheFolder: context.env.cacheFolder, beginInstall() { this.installed = {}; - this.tempFolders = []; }, endInstall(isCleanCache = true) { isCleanCache && this.cleanCache(); }, + // Полная очистка кэша загрузки cleanCache() { log.begin('Clean cache...'); - fs.rmSync(this.getTempFolderFor(), { recursive: true, force: true }); + fs.rmSync(this.getCacheFolderFor(), { recursive: true, force: true }); + log.begin('Done.'); + }, + // Очистка кэша для конкретного пакета + cleanCacheForPackege(packageId) { + log.begin(`Clean cache for ${packageId}...`); + fs.rmSync(this.getCacheFolderFor(packageId), { recursive: true, force: true }); log.begin('Done.'); }, - // Строим граф зависимостей по данным из указанной области async buildDependenciesGraph(location) { log.begin('Building dependencies graph...'); @@ -173,16 +177,15 @@ module.exports = function (context) { } }, - getTempFolderFor(packageId) { + getCacheFolderFor(packageId) { const result = packageId ? path.resolve(this.cacheFolder, packageId) : this.cacheFolder - packageId && this.tempFolders.push(result); return result; }, async downloadAndUnzipFrom(url, packageId) { - const tmpFolder = await this.getTempFolderFor(packageId); + const tmpFolder = await this.getCacheFolderFor(packageId); return new Promise((success, reject) => { // Если уже скачивали ранее и кэш сохранился используем его if (fs.existsSync(tmpFolder)) { @@ -342,6 +345,7 @@ module.exports = function (context) { throw new Error('Can not resolve dependencies!'); } log.debug(`Current version ${currentVer} will be updated to ${packageVer}.`); + this.cleanCacheForPackege(packageId); await this.removePackageFrom(location, packageId); } From 69f81eebda02e60741db0e350c91e16e00ff718d Mon Sep 17 00:00:00 2001 From: rpiontik Date: Wed, 13 Mar 2024 17:41:47 +0300 Subject: [PATCH 07/11] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=B2=D0=B5=D1=80=D1=81=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 67e81bc..1cb1ba0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "archpkg", - "version": "1.0.34", + "version": "1.0.35", "description": "The DocHub metamodel repository manager.", "private": false, "main": "index.js", From 4cf1bf1034d2ace4781f4bf7894fbe8e8c58c22b Mon Sep 17 00:00:00 2001 From: rpiontik Date: Wed, 13 Mar 2024 21:29:31 +0300 Subject: [PATCH 08/11] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=B4=D0=B5=D0=BA=D0=BB=D0=B0=D1=80=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D1=8E=20=D1=84=D0=B0=D0=B9=D0=BB=D0=BE=D0=B2=20=D0=B1?= =?UTF-8?q?=D0=B8=D0=B1=D0=BB=D0=B8=D0=BE=D1=82=D0=B5=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/package.json b/package.json index 1cb1ba0..911d002 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,10 @@ { "name": "archpkg", - "version": "1.0.35", + "version": "1.0.36", "description": "The DocHub metamodel repository manager.", "private": false, "main": "index.js", "module": "index.js", - "files": [ - "." - ], "homepage": "https://dochub.info", "bin": { "archpkg": "cli/main.js" From 65c8478e794a2601cc8816eb59b50b15ea683691 Mon Sep 17 00:00:00 2001 From: rpiontik Date: Thu, 9 May 2024 12:11:21 +0300 Subject: [PATCH 09/11] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D1=80=D0=B0?= =?UTF-8?q?=D0=B1=D0=BE=D1=82=D0=B0=D0=BD=D0=B0=20=D0=B8=D0=BD=D1=82=D0=B5?= =?UTF-8?q?=D0=B3=D1=80=D0=B0=D1=86=D0=B8=D1=8F=20=D1=81=20registry.dochub?= =?UTF-8?q?.info?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cli/repo.js | 53 +++++------------------------------------------------ 1 file changed, 5 insertions(+), 48 deletions(-) diff --git a/cli/repo.js b/cli/repo.js index 7a4f873..5cdd22b 100644 --- a/cli/repo.js +++ b/cli/repo.js @@ -32,8 +32,7 @@ module.exports = function (context) { guestToken: '/session/guest/token' }, repo: { - download: '/repo/download/', - metadata: '/repo/metadata/' + metadata: '/repo/v2/metadata/' } }, makeURL(route) { @@ -54,34 +53,6 @@ module.exports = function (context) { log.end(`Access token provided: ${content.token}`); } }, - async fetchReleasesByOwnerRepoVer(owner, repo, version) { - const fetchURL = this.makeURL(`https://api.github.com/repos/${owner}/${repo}/releases`).toString(); - log.begin(`Try to get fetch releases from ${fetchURL} for version [${version ? version : 'any'}]...`); - const response = await doRequest({ - url: fetchURL, - headers: { - 'User-Agent': 'archpkg', - 'Accept': 'application/vnd.github+json', - 'X-GitHub-Api-Version': '2022-11-28' - } - }); - const content = JSON.parse(response.body); - const versions = content.filter((item) => { - return !version || semver.satisfies(item.tag_name, version) || semver.satisfies(item.tag_name.slice(1), version); - }).sort((v1, v2) => { - const strvToNumber = function (rel) { - const struct = rel.tag_name.toString().replace('v', '').split('.'); - const result = - Number.parseInt(struct[0] || '0') * 1000000000 - + Number.parseInt(struct[1] || '0') * 1000000 - + Number.parseInt(struct[2] || '0') * 1000; - return result; - }; - return strvToNumber(v1) - strvToNumber(v2); - }); - log.end(`Found versions: ${versions.map(item => item.tag_name).join(', ')}.`); - return versions; - }, async fetchSourceOfPackage(package) { await this.getAccess(); const url = this.makeURL(`${this.routes.repo.metadata}${package}`).toString(); @@ -94,29 +65,15 @@ module.exports = function (context) { if (response.statusCode !== 200) throw new Error(`Error of resolve the download link of package ${package}. Response code ${response.statusCode} with body [${response.body}]`); const content = JSON.parse(response.body); - if (content.repo === '$built-in$') { + if (content.type === 'built-in') { log.end(`The package is built-in.`); return { source: 'built-in' } + } else { + log.end(`Link is found: ${content.source}`); + return content; } - const result = { - package - }; - - if (content.type==='github') { - log.debug(`GitHub location Owner: ${content.owner}, Repo: ${content.repo}`); - const releases = await this.fetchReleasesByOwnerRepoVer(content.owner, content.repo, package.split('@')[1]); - if (!releases || !releases.length) - throw new Error(`No found any release for ${$package}!`); - const release = releases.pop(); - result.source = `https://codeload.github.com/${content.owner}/${content.repo}/tar.gz/refs/tags/${release.tag_name}` - } else if (content.type==='direct') { - log.debug('Direct location'); - result.source = content.source; - } - log.end(`Link is found: ${result.source}`); - return result; }, }; } \ No newline at end of file From 523adfd71a495fe4f48b00b625c1ea40d0b82397 Mon Sep 17 00:00:00 2001 From: rpiontik Date: Thu, 9 May 2024 12:12:16 +0300 Subject: [PATCH 10/11] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=B2=D0=B5=D1=80=D1=81=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 911d002..2841771 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "archpkg", - "version": "1.0.36", + "version": "2.0.0", "description": "The DocHub metamodel repository manager.", "private": false, "main": "index.js", From d16894f09d09e03e71647dcc13922c00e809aa71 Mon Sep 17 00:00:00 2001 From: rpiontik Date: Thu, 9 May 2024 20:38:30 +0300 Subject: [PATCH 11/11] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=20=D0=BF=D1=83=D1=82=D1=8C=20=D0=BA=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cli/repo.js | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cli/repo.js b/cli/repo.js index 5cdd22b..ee4c11e 100644 --- a/cli/repo.js +++ b/cli/repo.js @@ -29,10 +29,10 @@ module.exports = function (context) { }, routes: { access: { - guestToken: '/session/guest/token' + guestToken: 'api/session/guest/token' }, repo: { - metadata: '/repo/v2/metadata/' + metadata: 'api/repo/v2/metadata/' } }, makeURL(route) { diff --git a/package.json b/package.json index 2841771..86f5c31 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "archpkg", - "version": "2.0.0", + "version": "2.0.1", "description": "The DocHub metamodel repository manager.", "private": false, "main": "index.js",