1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 | 'use strict';
|
14 |
|
15 | const path = require('path');
|
16 |
|
17 | const git = require('isomorphic-git');
|
18 | git.plugins.set('fs', require('fs'));
|
19 | const { debug } = require('@adobe/helix-log');
|
20 | const { resolveCommit, getObject } = require('./git');
|
21 | const { resolveRepositoryPath } = require('./utils');
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 | function createMiddleware(options) {
|
30 | |
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 | return (req, res, next) => {
|
42 |
|
43 | const { owner } = req.params;
|
44 | const repoName = req.params.repo;
|
45 | const refName = req.query.ref || 'master';
|
46 | let fpath = req.params[0] || '';
|
47 |
|
48 |
|
49 | while (fpath.length && fpath[0] === '/') {
|
50 |
|
51 | fpath = fpath.substr(1);
|
52 | }
|
53 |
|
54 | const repPath = resolveRepositoryPath(options, owner, repoName);
|
55 |
|
56 | async function dirEntryToJson(sha, dirPath) {
|
57 | const host = req.mappedSubDomain ? `localhost:${options.listen[req.protocol].port}` : req.headers.host;
|
58 | const url = `${req.protocol}://${host}${req.path}?ref=${refName}`;
|
59 | const gitUrl = `${req.protocol}://${host}/api/repos/${owner}/${repoName}/git/trees/${sha}`;
|
60 | const htmlUrl = `${req.protocol}://${host}/${owner}/${repoName}/tree/${refName}/${dirPath}`;
|
61 | return {
|
62 | type: 'dir',
|
63 | name: path.basename(dirPath),
|
64 | path: dirPath,
|
65 | sha,
|
66 | size: 0,
|
67 | url,
|
68 | html_url: htmlUrl,
|
69 | git_url: gitUrl,
|
70 | download_url: null,
|
71 | _links: {
|
72 | self: url,
|
73 | git: gitUrl,
|
74 | html: htmlUrl,
|
75 | },
|
76 | };
|
77 | }
|
78 |
|
79 | async function fileEntryToJson(sha, content, filePath, withContent) {
|
80 | const host = req.mappedSubDomain ? `localhost:${options.listen[req.protocol].port}` : req.headers.host;
|
81 | const url = `${req.protocol}://${host}${req.path}?ref=${refName}`;
|
82 | const gitUrl = `${req.protocol}://${host}/api/repos/${owner}/${repoName}/git/blobs/${sha}`;
|
83 | const htmlUrl = `${req.protocol}://${host}/${owner}/${repoName}/blob/${refName}/${filePath}`;
|
84 | const rawlUrl = `${req.protocol}://${host}/raw/${owner}/${repoName}/${refName}/${filePath}`;
|
85 | const result = {
|
86 | type: 'file',
|
87 | name: path.basename(filePath),
|
88 | path: filePath,
|
89 | sha,
|
90 | size: content.length,
|
91 | url,
|
92 | html_url: htmlUrl,
|
93 | git_url: gitUrl,
|
94 | download_url: rawlUrl,
|
95 | _links: {
|
96 | self: url,
|
97 | git: gitUrl,
|
98 | html: htmlUrl,
|
99 | },
|
100 | };
|
101 | if (withContent) {
|
102 | result.content = `${content.toString('base64')}\n`;
|
103 | result.encoding = 'base64';
|
104 | }
|
105 | return result;
|
106 | }
|
107 |
|
108 | async function treeEntriesToJson(entries, dirPath) {
|
109 | return Promise.all(entries.map(async (entry) => {
|
110 | if (entry.type === 'blob') {
|
111 | const { object: content } = await getObject(repPath, entry.oid);
|
112 | return fileEntryToJson(entry.oid, content, path.join(dirPath, entry.path), false);
|
113 | }
|
114 | return dirEntryToJson(entry.oid, path.join(dirPath, entry.path));
|
115 | }));
|
116 | }
|
117 |
|
118 | resolveCommit(repPath, refName)
|
119 | .then((commitOid) => git.readObject({ dir: repPath, oid: commitOid, filepath: fpath }))
|
120 | .then(({ type, oid, object }) => {
|
121 | if (type === 'blob') {
|
122 |
|
123 | return fileEntryToJson(oid, object, fpath, true);
|
124 | }
|
125 |
|
126 | return treeEntriesToJson(object.entries, fpath);
|
127 | })
|
128 | .then((json) => {
|
129 | res.json(json);
|
130 | })
|
131 | .catch((err) => {
|
132 |
|
133 | if (err.code === 'ResolveRefError') {
|
134 | debug(`[contentHandler] resource not found: ${err.message}`);
|
135 | res.status(404).json({
|
136 | message: `No commit found for the ref ${refName}`,
|
137 | documentation_url: 'https://developer.github.com/v3/repos/contents/',
|
138 | });
|
139 | } else if (err.code === 'TreeOrBlobNotFoundError') {
|
140 | debug(`[contentHandler] resource not found: ${err.message}`);
|
141 | res.status(404).json({
|
142 | message: 'Not Found',
|
143 | documentation_url: 'https://developer.github.com/v3/repos/contents/#get-contents',
|
144 | });
|
145 | } else {
|
146 | debug(`[contentHandler] code: ${err.code} message: ${err.message} stack: ${err.stack}`);
|
147 | next(err);
|
148 | }
|
149 | });
|
150 | };
|
151 | }
|
152 | module.exports = createMiddleware;
|