<commit_before>/**
 *      Install adapter
 *
 *      Copyright 2013-2021 bluefox <<EMAIL>>
 *
 *      MIT License
 *
 */

'use strict';

/** @class */
function Install(options) {
    const { tools, EXIT_CODES } = require('@iobroker/js-controller-common');
    const fs = require('fs-extra');
    const hostname = tools.getHostName();
    const path = require('path');
    const semver = require('semver');
    const child_process = require('child_process');
    const axios = require('axios');
    const PacketManager = require('./setupPacketManager');
    const osPlatform = require('os').platform();
    const deepClone = require('deep-clone');
    const { URL } = require('url');

    // todo solve it somehow
    const unsafePermAlways = [
        tools.appName.toLowerCase() + '.zwave',
        tools.appName.toLowerCase() + '.amazon-dash',
        tools.appName.toLowerCase() + '.xbox'
    ];

    const isRootOnUnix = typeof process.getuid === 'function' && process.getuid() === 0;

    options = options || {};

    if (!options.states) {
        throw new Error('Invalid arguments: states is missing');
    }
    if (!options.objects) {
        throw new Error('Invalid arguments: objects is missing');
    }
    if (!options.processExit) {
        throw new Error('Invalid arguments: processExit is missing');
    }
    if (!options.getRepository) {
        throw new Error('Invalid arguments: getRepository is missing');
    }

    const objects = options.objects;
    const states = options.states;
    const processExit = options.processExit;
    const getRepository = options.getRepository;
    const params = options.params || {};
    let mime;

    let packetManager;

    // TODO: promisify States at some point
    /** @type {(stateId: string) => Promise<void>} */
    const delStateAsync = tools.promisify(states.delState, states);

    /** @type {(pattern: string) => Promise<string[]>} */
    const getKeysAsync = tools.promisify(states.getKeys, states);

    const tarballRegex = /\/tarball\/[^/]+$/;

    const Upload = require('./setupUpload');
    const upload = new Upload(options);

    async function enableAdapters(adapters, enabled) {
        if (adapters && adapters.length) {
            const ts = Date.now();
            for (let i = 0; i < adapters.length; i++) {
                const updatedObj = {
                    common: {
                        enabled
                    },
                    from: `system.host.${tools.getHostName()}.cli`,
                    ts
                };
                console.log(`host.${hostname} Adapter "${adapters[i]._id}" is ${enabled ? 'started' : 'stopped.'}`);
                await objects.extendObjectAsync(adapters[i]._id, updatedObj);
            }
        }
    }

    /**
     * Download given packet
     *
     * @param {string} repoUrl
     * @param {string} packetName
     * @param {object?} options
     * @param {object[]?} stoppedList
     * @return {Promise<void>}
     */
    this.downloadPacket = async function (repoUrl, packetName, options, stoppedList) {
        let url;
        if (!options || typeof options !== 'object') {
            options = {};
        }

        if (!repoUrl || typeof repoUrl !== 'object') {
            try {
                const result = await getRepository(repoUrl, params);
                repoUrl = result;
            } catch (err) {
                return processExit(err);
            }
        }

        let debug = false;
        for (let i = 0; i < process.argv.length; i++) {
            if (process.argv[i] === '--debug') {
                debug = true;
                break;
            }
        }

        let version;
        // check if the adapter has format adapter@1.0.0
        if (packetName.includes('@')) {
            const parts = packetName.split('@');
            packetName = parts[0];
            version = parts[1];
        } else {
            // always take version from repository
            if (repoUrl[packetName] && repoUrl[packetName].version) {
                version = repoUrl[packetName].version;
            } else {
                version = '';
            }
        }
        options.packetName = packetName;

        const sources = repoUrl;
        options.unsafePerm = sources[packetName] && sources[packetName].unsafePerm;

        // Check if flag stopBeforeUpdate is true
        if (sources[packetName] && sources[packetName].stopBeforeUpdate && !stoppedList) {
            const arr = await objects.getObjectListAsync({
                startkey: `system.adapter.${packetName}.`,
                endkey: `system.adapter.${packetName}.\u9999`
            });

            stoppedList = [];

            if (arr) {
                for (let id = 0; id < arr.rows.length; id++) {
                    // stop only started instances on this host
                    if (arr.rows[id].value.common.enabled && hostname === arr.rows[id].value.common.host) {
                        stoppedList.push(arr.rows[id].value);
                    }
                }
            }

            await enableAdapters(stoppedList, false);
        }

        // try to extract the information from local sources-dist.json
        if (!sources[packetName]) {
            try {
                const sourcesDist = fs.readJSONSync(__dirname + '/../../conf/sources-dist.json');
                sources[packetName] = sourcesDist[packetName];
            } catch {
                // OK
            }
        }

        if (sources[packetName]) {
            url = sources[packetName].url;

            if (
                url &&
                packetName === 'js-controller' &&
                fs.existsSync(`${__dirname}/../../../../node_modules/${tools.appName}.js-controller`)
            ) {
                url = null;
            }

            if (!url && packetName !== 'example') {<commit_msg>stop adapters on win prior update to prevent EBUSY (#1612)<commit_after>/**
 *      Install adapter
 *
 *      Copyright 2013-2021 bluefox <<EMAIL>>
 *
 *      MIT License
 *
 */

'use strict';

/** @class */
function Install(options) {
    const { tools, EXIT_CODES } = require('@iobroker/js-controller-common');
    const fs = require('fs-extra');
    const hostname = tools.getHostName();
    const path = require('path');
    const semver = require('semver');
    const child_process = require('child_process');
    const axios = require('axios');
    const PacketManager = require('./setupPacketManager');
    const osPlatform = require('os').platform();
    const deepClone = require('deep-clone');
    const { URL } = require('url');

    // todo solve it somehow
    const unsafePermAlways = [
        tools.appName.toLowerCase() + '.zwave',
        tools.appName.toLowerCase() + '.amazon-dash',
        tools.appName.toLowerCase() + '.xbox'
    ];

    const isRootOnUnix = typeof process.getuid === 'function' && process.getuid() === 0;

    options = options || {};

    if (!options.states) {
        throw new Error('Invalid arguments: states is missing');
    }
    if (!options.objects) {
        throw new Error('Invalid arguments: objects is missing');
    }
    if (!options.processExit) {
        throw new Error('Invalid arguments: processExit is missing');
    }
    if (!options.getRepository) {
        throw new Error('Invalid arguments: getRepository is missing');
    }

    const objects = options.objects;
    const states = options.states;
    const processExit = options.processExit;
    const getRepository = options.getRepository;
    const params = options.params || {};
    let mime;

    let packetManager;

    // TODO: promisify States at some point
    /** @type {(stateId: string) => Promise<void>} */
    const delStateAsync = tools.promisify(states.delState, states);

    /** @type {(pattern: string) => Promise<string[]>} */
    const getKeysAsync = tools.promisify(states.getKeys, states);

    const tarballRegex = /\/tarball\/[^/]+$/;

    const Upload = require('./setupUpload');
    const upload = new Upload(options);

    async function enableAdapters(adapters, enabled) {
        if (adapters && adapters.length) {
            const ts = Date.now();
            for (let i = 0; i < adapters.length; i++) {
                const updatedObj = {
                    common: {
                        enabled
                    },
                    from: `system.host.${tools.getHostName()}.cli`,
                    ts
                };
                console.log(`host.${hostname} Adapter "${adapters[i]._id}" is ${enabled ? 'started' : 'stopped.'}`);
                await objects.extendObjectAsync(adapters[i]._id, updatedObj);
            }
        }
    }

    /**
     * Download given packet
     *
     * @param {string} repoUrl
     * @param {string} packetName
     * @param {object?} options
     * @param {object[]?} stoppedList
     * @return {Promise<void>}
     */
    this.downloadPacket = async function (repoUrl, packetName, options, stoppedList) {
        let url;
        if (!options || typeof options !== 'object') {
            options = {};
        }

        if (!repoUrl || typeof repoUrl !== 'object') {
            try {
                const result = await getRepository(repoUrl, params);
                repoUrl = result;
            } catch (err) {
                return processExit(err);
            }
        }

        let debug = false;
        for (let i = 0; i < process.argv.length; i++) {
            if (process.argv[i] === '--debug') {
                debug = true;
                break;
            }
        }

        let version;
        // check if the adapter has format adapter@1.0.0
        if (packetName.includes('@')) {
            const parts = packetName.split('@');
            packetName = parts[0];
            version = parts[1];
        } else {
            // always take version from repository
            if (repoUrl[packetName] && repoUrl[packetName].version) {
                version = repoUrl[packetName].version;
            } else {
                version = '';
            }
        }
        options.packetName = packetName;

        const sources = repoUrl;
        options.unsafePerm = sources[packetName] && sources[packetName].unsafePerm;

        // Check if flag stopBeforeUpdate is true or on windows we stop because of issue #1436
        if (
            ((sources[packetName] && sources[packetName].stopBeforeUpdate) || process.platform === 'win32') &&
            !stoppedList
        ) {
            const arr = await objects.getObjectListAsync({
                startkey: `system.adapter.${packetName}.`,
                endkey: `system.adapter.${packetName}.\u9999`
            });

            stoppedList = [];

            if (arr) {
                for (const row of arr.rows) {
                    // stop only started instances on this host
                    if (row.value.common.enabled && hostname === row.value.common.host) {
                        stoppedList.push(row.value);
                    }
                }
            }

            await enableAdapters(stoppedList, false);
        }

        // try to extract the information from local sources-dist.json
        if (!sources[packetName]) {
            try {
                const sourcesDist = fs.readJSONSync(__dirname + '/../../conf/sources-dist.json');
                sources[packetName] = sourcesDist[packetName];
            } catch {
                // OK
            }
        }

        if (sources[packetName]) {
            url = sources[packetName].url;

            if (
                url &&
                packetName === 'js-controller' &&
                fs.existsSync(`${__dirname}/../../../../node_modules/${tools.appName}.js-controller`)
            ) {
                url = null;
            }

            if (!url && packetName !== 'example') {
{'fraction_non_alphanumeric': 0.13324337999662675, 'fraction_numerical': 0.004300893911283522, 'mean_word_length': 1.7604748603351956, 'pattern_counts': {'":': 0, '<': 18, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3622246', 'n_tokens_mistral': 3250, 'n_tokens_neox': 3099, 'n_words': 760}