105 lines
3.4 KiB
JavaScript
105 lines
3.4 KiB
JavaScript
'use strict';
|
|
|
|
const fs = require('fs');
|
|
const export_helpers_prepare = require('../../export/helpers/prepare.cjs');
|
|
const download_github_hash = require('./hash.cjs');
|
|
const download_api_download = require('../api/download.cjs');
|
|
const download_helpers_unzip = require('../helpers/unzip.cjs');
|
|
require('pathe');
|
|
require('../api/index.cjs');
|
|
require('../api/cache.cjs');
|
|
require('crypto');
|
|
require('../../misc/scan.cjs');
|
|
require('../api/config.cjs');
|
|
require('../api/fetch.cjs');
|
|
require('fs/promises');
|
|
require('extract-zip');
|
|
|
|
async function findMatchingDirs(rootDir, hash) {
|
|
const matches = [];
|
|
const files = await fs.promises.readdir(rootDir);
|
|
for (let i = 0; i < files.length; i++) {
|
|
const file = files[i];
|
|
const lastChunk = file.split("-").pop();
|
|
if (lastChunk.length < 4 || lastChunk !== hash.slice(0, lastChunk.length)) {
|
|
continue;
|
|
}
|
|
const stat = await fs.promises.stat(rootDir + "/" + file);
|
|
if (stat.isDirectory()) {
|
|
matches.push(file);
|
|
}
|
|
}
|
|
return matches;
|
|
}
|
|
async function downloadGitHubRepo(options) {
|
|
const hash = await download_github_hash.getGitHubRepoHash(options);
|
|
const ifModifiedSince = options.ifModifiedSince;
|
|
if (ifModifiedSince) {
|
|
const expectedHash = typeof ifModifiedSince === "string" ? ifModifiedSince : ifModifiedSince.downloadType === "github" ? ifModifiedSince.hash : null;
|
|
if (hash === expectedHash) {
|
|
return "not_modified";
|
|
}
|
|
}
|
|
options.target = options.target.replace("{hash}", hash);
|
|
const rootDir = options.target = await export_helpers_prepare.prepareDirectoryForExport(options);
|
|
const archiveTarget = rootDir + "/" + hash + ".zip";
|
|
let exists = false;
|
|
try {
|
|
const stat = await fs.promises.stat(archiveTarget);
|
|
exists = stat.isFile();
|
|
} catch (err) {
|
|
}
|
|
if (!exists) {
|
|
const uri = `https://api.github.com/repos/${options.user}/${options.repo}/zipball/${hash}`;
|
|
await download_api_download.downloadFile(
|
|
{
|
|
uri,
|
|
headers: {
|
|
Accept: "application/vnd.github.v3+json",
|
|
Authorization: "token " + options.token
|
|
}
|
|
},
|
|
archiveTarget
|
|
);
|
|
}
|
|
const files = await fs.promises.readdir(rootDir);
|
|
const hashSearch = "-" + hash;
|
|
for (let i = 0; i < files.length; i++) {
|
|
const file = files[i];
|
|
if (file === hash + ".zip") {
|
|
continue;
|
|
}
|
|
const filename = rootDir + "/" + files[i];
|
|
const stat = await fs.promises.lstat(filename);
|
|
const isDir = stat.isDirectory();
|
|
if (
|
|
// Remove symbolic links
|
|
stat.isSymbolicLink() || // Remove if directory matches hash to avoid errors extracting zip
|
|
isDir && filename.slice(0 - hashSearch.length) === hashSearch || // Remove if directory and cleanupOldDirectories is not disabled
|
|
isDir && options.cleanupOldDirectories !== false || // Remove if file and cleanupOldFiles is enabled
|
|
!isDir && options.cleanupOldFiles
|
|
) {
|
|
try {
|
|
await fs.promises.rm(filename, {
|
|
force: true,
|
|
recursive: true
|
|
});
|
|
} catch (err) {
|
|
}
|
|
}
|
|
}
|
|
await download_helpers_unzip.unzip(archiveTarget, rootDir);
|
|
const matchingDirs = await findMatchingDirs(rootDir, hash);
|
|
if (matchingDirs.length !== 1) {
|
|
throw new Error(`Error unpacking ${hash}.zip`);
|
|
}
|
|
const contentsDir = rootDir + "/" + matchingDirs[0];
|
|
return {
|
|
downloadType: "github",
|
|
rootDir,
|
|
contentsDir,
|
|
hash
|
|
};
|
|
}
|
|
|
|
exports.downloadGitHubRepo = downloadGitHubRepo;
|