Skip to content

Commit 706f586

Browse files
committed
Get file details API.
1 parent 2aa1e08 commit 706f586

File tree

7 files changed

+139
-64
lines changed

7 files changed

+139
-64
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ git clone http://127.0.0.1:2018/admin/test.git test
99
git fetch http://127.0.0.1:2018/admin/test.git test
1010
```
1111

12-
## Git Protocols and APIs
12+
## Git APIs
1313

1414
Serving content of a file in a git repo.
1515

api-doc/repos.http

+32-11
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,6 @@
1111
GET {{baseUrl}}/api/user/orgs
1212
Content-Type: {{contentType}}
1313

14-
### 获取 README
15-
16-
GET {{baseUrl}}/api/repos/admin/test/readme
17-
Content-Type: {{contentType}}
18-
1914
### 用户项目列表
2015

2116
@username = admin
@@ -41,10 +36,10 @@ Content-Type: {{contentType}}
4136
### 项目文件列表
4237

4338
@id = 13
44-
45-
# @apiParam {String} id 项目ID
46-
# @apiParam {String} [path] 存储库中的路径
47-
# @apiParam {String} [ref] 存储库分支或标记的名称,如果没有给出默认分支
39+
40+
# @apiParam {String} id 项目ID
41+
# @apiParam {String} [path] 存储库中的路径
42+
# @apiParam {String} [ref] 存储库分支或标记的名称,如果没有给出默认分支
4843
# @apiParam {String} [recursive] 用于获取递归树的布尔值(默认为false)
4944

5045
GET {{baseUrl}}/api/repos/{{id}}/tree
@@ -56,11 +51,37 @@ Content-Type: {{contentType}}
5651
# @apiSuccess message 提交commit内容 "Add repo tree API parameter path.\n"
5752
# @apiSuccess messageRaw 提交commit内容 "Add repo tree API parameter path.\n"
5853
# @apiSuccess owner 返回 { "name": "jaywcjlove", "email": "398188662@qq.com" }
59-
# @apiSuccess amend
54+
# @apiSuccess amend
6055
# @apiSuccess time 535736727
6156
# @apiSuccess date 2018-08-31T17:32:07.000Z"
6257
# @apiSuccess timeMs 535736727000
6358
# @apiSuccess timeOffset 80
6459
# @apiSuccess isFile alse
6560
# @apiSuccess path 返回路径
66-
# @apiSuccess entryCount
61+
# @apiSuccess entryCount
62+
63+
64+
65+
### 获取 README
66+
67+
GET {{baseUrl}}/api/repos/{{username}}/{{repo}}/readme
68+
Content-Type: {{contentType}}
69+
70+
71+
### 获取文件详情
72+
73+
@ref = master
74+
# @filepath = conf/sequelize.js
75+
@filepath = README.md
76+
@repo2 = gitke
77+
78+
# http://localhost:19870/admin/gitke/blob/master/conf/conf.js
79+
GET {{baseUrl}}/api/repos/{{username}}/{{repo2}}/blob/{{ref}}/{{filepath}}
80+
Content-Type: {{contentType}}
81+
82+
### 获取文件内容
83+
84+
# http://localhost:19870/admin/gitke/raw/master/conf/conf.js
85+
# /:owner/:repo/raw/:ref/*
86+
87+
GET {{baseUrl}}/{{username}}/{{repo2}}/raw/{{ref}}/{{filepath}}

api-doc/user.http

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,4 @@ Content-Type: {{contentType}}
4747
### 用户列表
4848

4949
GET {{baseUrl}}/api/users
50-
Content-Type: {{contentType}}
50+
Content-Type: {{contentType}}

src/controller/git/raw.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,4 @@ async function rawHandler(ctx, next) {
8989
ctx.body = blob.content();
9090
}
9191

92-
module.exports = rawHandler;
92+
module.exports = rawHandler;

src/controller/git/repos/index.js

+57-4
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,40 @@ module.exports = {
116116
ctx.body = { message: err.message, ...err }
117117
}
118118
},
119+
fileDetail: async (ctx) => {
120+
const { owner, repo, ref } = ctx.params;
121+
const { reposPath } = ctx.state.conf;
122+
const currentRepoPath = PATH.join(reposPath, owner, `${repo}.git`);
123+
const filePath = ctx.params[0];
124+
try {
125+
const porps = {};
126+
const gitRepo = await Git.Repository.open(currentRepoPath);
127+
const reqRef = await gitRepo.getReference(ref);
128+
const obj = await reqRef.peel(Git.Object.TYPE.COMMIT);
129+
const commitlookup = await Git.Commit.lookup(gitRepo, obj.id());
130+
const tree = await commitlookup.getTree();
131+
const entry = await tree.getEntry(filePath);
132+
porps.id = entry.oid();
133+
porps.ref = reqRef.name();
134+
135+
const blob = await entry.getBlob()
136+
ctx.body = {
137+
...porps,
138+
content: blob.toString(),
139+
parsePath: PATH.parse(filePath),
140+
path: filePath,
141+
has: blob.id,
142+
refName: blob.id,
143+
filemode: blob.filemode(),
144+
rawsize: blob.rawsize(),
145+
}
146+
blob.free();
147+
tree.free();
148+
} catch (err) {
149+
ctx.response.status = err.statusCode || err.status || 500;
150+
ctx.body = { message: err.message, ...err }
151+
}
152+
},
119153
reposTree: async (ctx) => {
120154
const { id } = ctx.params;
121155
const { userInfo } = ctx.session;
@@ -142,7 +176,7 @@ module.exports = {
142176
const { reposPath } = ctx.state.conf;
143177
const currentRepoPath = PATH.join(reposPath, projects.namespace.name, `${projects.name}.git`);
144178
const gitRepo = await Git.Repository.open(currentRepoPath);
145-
179+
146180
// 空仓库返回 README.md 说明内容
147181
let emptyRepoReadme = await readFile(PATH.join(__dirname, 'EmptyRepo.md'));
148182
if (gitRepo.isEmpty() === 1) {
@@ -184,14 +218,33 @@ module.exports = {
184218

185219
// 参数 path 处理,存储库中的路径
186220
if (ctx.query.path) {
221+
body.parsePath = PATH.parse(ctx.query.path);
187222
let treeObj = await commit.getEntry(ctx.query.path);
188223
if (treeObj.isFile()) {
189-
body.isFile = treeObj.isFile();
190-
treeObj = await treeObj.getBlob();
224+
// try {
225+
// // repo.getCommit("bf1da765e357a9b936d6d511f2c7b78e0de53632");
226+
// // const commit = await Git.Commit.lookup(gitRepo, treeObj.oid())
227+
// const commits = await gitRepo.getCommit(treeObj.oid())
228+
// console.log('entry:', commits.__proto__)
229+
// } catch (error) {
230+
// console.log('error:', error)
231+
// }
232+
const entry = await commit.getEntry(treeObj.path());
233+
const local = await treeObj.toObject(gitRepo)
234+
// const aa = await local.lookupByPath(treeObj.path(), Git.Object.TYPE.BLOB)
235+
// console.log('treeObj:', treeObj.__proto__)
236+
// console.log('local:', local.__proto__)
237+
// console.log('local:', local.owner())
238+
// console.log('local:', local.lookupByPath(treeObj.path(), Git.Object.TYPE.BLOB))
239+
// console.log('treeObj:', treeObj.path())
240+
const blob = await Git.Blob.lookup(gitRepo, treeObj.oid());
241+
body.rawsize = blob.rawsize();
242+
body.readmeContent = blob.content().toString();
243+
body.isFile = true;
191244
body.path = ctx.query.path;
192245
body.tree = [];
193-
body.readmeContent = treeObj.toString();
194246
ctx.body = body;
247+
blob.free()
195248
return;
196249
}
197250
treeObj = await treeObj.getTree(treeObj.sha());

src/controller/git/repos/util.js

+45-45
Original file line numberDiff line numberDiff line change
@@ -111,51 +111,51 @@ exports.getEntrysCommit = (tree = [], repo, firstCommitOnMasterSha) => {
111111
if (!tree || tree.length === 0) return [];
112112
return Promise.all(tree.map(async (item) => {
113113
const props = { ...item };
114-
// if (item.path) {
115-
// let root = null;
116-
// const walk = repo.createRevWalk();
117-
// try {
118-
// walk.pushGlob('refs/heads/*');
119-
// // walk.pushRef('refs/heads/master')
120-
// // walk.pushHead()
121-
// walk.sorting(nodegit.Revwalk.SORT.TIME, nodegit.Revwalk.SORT.REVERSE);
122-
// await (async function step() {
123-
// let oid = null;
124-
// try {
125-
// oid = await walk.next();
126-
// } catch (error) {
127-
// return;
128-
// }
129-
// if (oid == null) {
130-
// return;
131-
// }
132-
// const commit = await nodegit.Commit.lookup(repo, oid)
133-
// let entry = null;
134-
// try {
135-
// entry = await commit.getEntry(item.path);
136-
// }
137-
// catch (err) {
138-
// if (err.errno !== -3) {
139-
// throw err;
140-
// }
141-
// }
142-
// if (entry != null) {
143-
// root = commit;
144-
// if (entry.oid() === item.id) {
145-
// return;
146-
// }
147-
// }
148-
// await step();
149-
// })()
150-
// }
151-
// finally {
152-
// walk.free();
153-
// }
154-
// const string = root.message();
155-
// const sha = root.sha();
156-
// props.message = string;
157-
// props.sha = sha;
158-
// }
114+
if (item.path) {
115+
let root = null;
116+
const walk = repo.createRevWalk();
117+
try {
118+
walk.pushGlob('refs/heads/*');
119+
// walk.pushRef('refs/heads/master')
120+
// walk.pushHead()
121+
walk.sorting(nodegit.Revwalk.SORT.TIME, nodegit.Revwalk.SORT.REVERSE);
122+
await (async function step() {
123+
let oid = null;
124+
try {
125+
oid = await walk.next();
126+
} catch (error) {
127+
return;
128+
}
129+
if (oid == null) {
130+
return;
131+
}
132+
const commit = await nodegit.Commit.lookup(repo, oid)
133+
let entry = null;
134+
try {
135+
entry = await commit.getEntry(item.path);
136+
}
137+
catch (err) {
138+
if (err.errno !== -3) {
139+
throw err;
140+
}
141+
}
142+
if (entry != null) {
143+
root = commit;
144+
if (entry.oid() === item.id) {
145+
return;
146+
}
147+
}
148+
await step();
149+
})()
150+
}
151+
finally {
152+
walk.free();
153+
}
154+
const string = root.message();
155+
const sha = root.sha();
156+
props.message = string;
157+
props.sha = sha;
158+
}
159159

160160
// if (item.path && (item.type === 'commit' || item.type === 'blob')) {
161161
// // https://github.com/nodegit/nodegit/issues/220

src/routes/git/repos.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ router
1111
.get('/repos/:id/tree', repos.reposTree)
1212
.get('/repos/:owner/:repo', repos.detail)
1313
.get('/repos/:owner/:repo/readme', repos.readme)
14+
.get('/repos/:owner/:repo/blob/:ref/*', repos.fileDetail)
1415
.get('/orgs/:org/repos', repos.orgReposList)
1516
.post('/orgs/:org/repos', repos.created)
1617

17-
module.exports = router;
18+
module.exports = router;

0 commit comments

Comments
 (0)