| 680 | } |
| 681 | |
| 682 | static async export(domainId: string, pidFilter = '') { |
| 683 | console.log('Exporting problems...'); |
| 684 | const tmpdir = path.join(os.tmpdir(), 'hydro', `${Math.random()}.export`); |
| 685 | await fs.mkdir(tmpdir); |
| 686 | const pdocs = await ProblemModel.getMulti( |
| 687 | domainId, pidFilter ? { pid: new RegExp(pidFilter) } : {}, |
| 688 | ProblemModel.PROJECTION_PUBLIC, |
| 689 | ).toArray(); |
| 690 | if (process.env.HYDRO_CLI) logger.info(`Exporting ${pdocs.length} problems`); |
| 691 | for (const pdoc of pdocs) { |
| 692 | if (process.env.HYDRO_CLI) logger.info(`Exporting problem ${pdoc.pid || (`P${pdoc.docId}`)} (${pdoc.title})`); |
| 693 | const problemPath = path.join(tmpdir, `${pdoc.docId}`); |
| 694 | await fs.mkdir(problemPath); |
| 695 | const problemYaml = path.join(problemPath, 'problem.yaml'); |
| 696 | const problemYamlContent = yaml.dump({ |
| 697 | pid: pdoc.pid || `P${pdoc.docId}`, |
| 698 | owner: pdoc.owner, |
| 699 | title: pdoc.title, |
| 700 | tag: pdoc.tag, |
| 701 | nSubmit: pdoc.nSubmit, |
| 702 | nAccept: pdoc.nAccept, |
| 703 | difficulty: pdoc.difficulty, |
| 704 | }); |
| 705 | await fs.writeFile(problemYaml, problemYamlContent); |
| 706 | try { |
| 707 | const c = JSON.parse(pdoc.content); |
| 708 | for (const key of Object.keys(c)) { |
| 709 | const problemContent = path.join(problemPath, `problem_${key}.md`); |
| 710 | await fs.writeFile(problemContent, typeof c[key] === 'string' ? c[key] : JSON.stringify(c[key])); |
| 711 | } |
| 712 | } catch (e) { |
| 713 | const problemContent = path.join(problemPath, 'problem.md'); |
| 714 | await fs.writeFile(problemContent, pdoc.content); |
| 715 | } |
| 716 | if ((pdoc.data || []).length) { |
| 717 | const testdataPath = path.join(problemPath, 'testdata'); |
| 718 | await fs.mkdir(testdataPath); |
| 719 | for (const file of pdoc.data) { |
| 720 | const stream = await storage.get(`problem/${domainId}/${pdoc.docId}/testdata/${file.name}`); |
| 721 | const buf = await streamToBuffer(stream); |
| 722 | const testdataFile = path.join(testdataPath, file.name); |
| 723 | await fs.writeFile(testdataFile, buf); |
| 724 | } |
| 725 | } |
| 726 | if ((pdoc.additional_file || []).length) { |
| 727 | const additionalPath = path.join(problemPath, 'additional_file'); |
| 728 | await fs.mkdir(additionalPath); |
| 729 | for (const file of pdoc.additional_file) { |
| 730 | const stream = await storage.get(`problem/${domainId}/${pdoc.docId}/additional_file/${file.name}`); |
| 731 | const buf = await streamToBuffer(stream); |
| 732 | const additionalFile = path.join(additionalPath, file.name); |
| 733 | await fs.writeFile(additionalFile, buf); |
| 734 | } |
| 735 | } |
| 736 | } |
| 737 | const target = `${process.cwd()}/problem-${domainId}-${new Date().toISOString().replace(':', '-').split(':')[0]}.zip`; |
| 738 | const res = child.spawnSync('zip', ['-r', target, '.'], { cwd: tmpdir, stdio: 'inherit' }); |
| 739 | if (res.error) throw res.error; |