1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 | 'use strict';
|
14 |
|
15 | const { join: joinPaths } = require('path');
|
16 | const { debug } = require('@adobe/helix-log');
|
17 | const { resolveTree, getObject } = require('./git');
|
18 | const { resolveRepositoryPath } = require('./utils');
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 | function createMiddleware(options) {
|
27 | |
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 | return (req, res, next) => {
|
39 |
|
40 | const { owner } = req.params;
|
41 | const repoName = req.params.repo;
|
42 | const refOrSha = req.params.ref_or_sha;
|
43 | const recursive = typeof req.query.recursive !== 'undefined' && req.query.recursive !== '';
|
44 | const host = req.mappedSubDomain ? `localhost:${options.listen[req.protocol].port}` : req.headers.host;
|
45 |
|
46 | const repPath = resolveRepositoryPath(options, owner, repoName);
|
47 |
|
48 | async function dirEntryToJson({
|
49 | oid: sha, type, path, mode,
|
50 | }) {
|
51 | return {
|
52 | path,
|
53 | mode,
|
54 | type,
|
55 | sha,
|
56 | url: `${req.protocol}://${host}/api/repos/${owner}/${repoName}/git/trees/${sha}`,
|
57 | };
|
58 | }
|
59 |
|
60 | async function fileEntryToJson({
|
61 | oid: sha, type, path, mode,
|
62 | }) {
|
63 | const { object: content } = await getObject(repPath, sha);
|
64 |
|
65 | return {
|
66 | path,
|
67 | mode,
|
68 | type,
|
69 | sha,
|
70 | size: content.length,
|
71 | url: `${req.protocol}://${host}/api/repos/${owner}/${repoName}/git/blobs/${sha}`,
|
72 | };
|
73 | }
|
74 |
|
75 | async function collectTreeEntries(tree, result, treePath, deep) {
|
76 | const entries = tree.entries.map(({
|
77 | oid, type, mode, path,
|
78 | }) => {
|
79 | return {
|
80 | oid, type, mode, path: joinPaths(treePath, path),
|
81 | };
|
82 | });
|
83 | result.push(...entries);
|
84 | if (deep) {
|
85 | const treeEntries = entries.filter((entry) => entry.type === 'tree');
|
86 | for (let i = 0; i < treeEntries.length; i += 1) {
|
87 | const { oid, path } = treeEntries[i];
|
88 |
|
89 | const { object: subTree } = await getObject(repPath, oid);
|
90 | await collectTreeEntries(subTree, result, path, deep);
|
91 | }
|
92 | }
|
93 | return result;
|
94 | }
|
95 |
|
96 | async function treeEntriesToJson(tree, deep) {
|
97 | const result = [];
|
98 | await collectTreeEntries(tree, result, '', deep);
|
99 | return Promise.all(result.map(async (entry) => {
|
100 |
|
101 | return entry.type === 'blob'
|
102 | ? fileEntryToJson(entry) : dirEntryToJson(entry);
|
103 | }));
|
104 | }
|
105 |
|
106 | resolveTree(repPath, refOrSha)
|
107 | .then(async ({ oid: sha, object: tree }) => {
|
108 | res.json({
|
109 | sha,
|
110 | url: `${req.protocol}://${host}/api/repos/${owner}/${repoName}/git/trees/${sha}`,
|
111 | tree: await treeEntriesToJson(tree, recursive),
|
112 | truncated: false,
|
113 | });
|
114 | })
|
115 | .catch((err) => {
|
116 |
|
117 | if (err.code === 'ReadObjectFail' || err.code === 'ResolveRefError') {
|
118 | debug(`[treeHandler] resource not found: ${err.message}`);
|
119 | res.status(404).json({
|
120 | message: 'Not Found',
|
121 | documentation_url: 'https://developer.github.com/v3/git/trees/#get-a-tree',
|
122 | });
|
123 | } else {
|
124 | debug(`[treeHandler] code: ${err.code} message: ${err.message} stack: ${err.stack}`);
|
125 | next(err);
|
126 | }
|
127 | });
|
128 | };
|
129 | }
|
130 | module.exports = createMiddleware;
|