2 回答

TA贡献1828条经验 获得超3个赞
您可以从用于递归遍历目录的 walk 函数中获得一些灵感。从那里。它看起来像这样:
async function walk(entry, isRoot) {
if (isRoot){
return await processEntry(entry);
}
let files = await getTreeEntryFromTree(repository, entry.oid);
files = await Promise.all(files.data.viewer.repository.object.entries.map(async file => {
return await processEntry(file);
}));
return files.reduce((all, folderContents) => all.concat(folderContents), []);
}
async function processEntry(entry){
if (entry.type === "tree") {
return walk(entry, false);
} else {
let res = await getBlob(repository, entry.oid);
return [{
name: entry.name,
oid: entry.oid,
data:res.data.viewer.repository.object.text
}];
}
}
因此,它只是将目录替换为树,并在返回文件时请求每个文件的数据内容。
源插件的以下代码(不含 ) :gatsby-node.jscreateSchemaCustomization
const { ApolloClient } = require("apollo-client")
const { InMemoryCache } = require("apollo-cache-inmemory")
const { HttpLink } = require("apollo-link-http")
const fetch = require("node-fetch")
const gql = require("graphql-tag")
const { setContext } = require('apollo-link-context');
const token = "YOUR_TOKEN";
const repository = "YOUR_REPO";
const authLink = setContext((_, { headers }) => {
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : null,
}
}
});
const defaultOptions = {
watchQuery: {
fetchPolicy: 'no-cache',
errorPolicy: 'ignore',
},
query: {
fetchPolicy: 'no-cache',
errorPolicy: 'all',
},
}
const client = new ApolloClient({
link: authLink.concat(new HttpLink({ uri: 'https://api.github.com/graphql', fetch: fetch })),
cache: new InMemoryCache(),
defaultOptions: defaultOptions,
});
exports.sourceNodes = async function sourceNodes(
{
actions,
cache,
createContentDigest,
createNodeId,
getNodesByType,
getNode,
},
pluginOptions
) {
const { createNode, touchNode, deleteNode } = actions
const { data } = await getTreeFromRepo(repository)
let sourceData = data;
fileArr = []
sourceData.viewer.repository.object.entries.map(it => {
fileArr.push(walk(it, true))
});
let res = await Promise.all(fileArr)
let result = res.flat();
console.log(result);
console.log(`got ${result.length} results`);
return
}
async function walk(entry, isRoot) {
if (isRoot){
return await processEntry(entry);
}
let files = await getTreeEntryFromTree(repository, entry.oid);
files = await Promise.all(files.data.viewer.repository.object.entries.map(async file => {
return await processEntry(file);
}));
return files.reduce((all, folderContents) => all.concat(folderContents), []);
}
async function processEntry(entry){
if (entry.type === "tree") {
return walk(entry, false);
} else {
let res = await getBlob(repository, entry.oid);
return [{
name: entry.name,
oid: entry.oid,
data:res.data.viewer.repository.object.text
}];
}
}
async function getTreeFromRepo(repo) {
return await client.query({
query: gql`
query {
viewer {
repository(name: "${repo}") {
object(expression: "master:") {
... on Tree {
entries {
name
oid
type
}
}
}
}
}
}
`,
})
}
async function getTreeEntryFromTree(repo, oid) {
return await client.query({
query: gql`
query getTree($id: GitObjectID!) {
viewer {
repository(name: "${repo}") {
object(oid: $id) {
... on Tree {
entries {
name
oid
type
}
}
}
}
}
}
`,
variables: {
id: oid
}
})
}
async function getBlob(repo, oid){
return await client.query({
query: gql`
query getFile($id: GitObjectID!) {
viewer {
repository(name: "${repo}") {
object(oid: $id) {
... on Blob {
text
}
}
}
}
}
`,
variables: {
id: oid
}
})
}
您需要在上面的代码中替换 Github 令牌和存储库名称。
它返回一个包含文件内容、名称和 oid 的对象数组
请注意,使用二进制文件的返回:... on Blob { text }null
文本(字符串)UTF8 文本数据,如果 Blob 是二进制的,则为空
此外,还可以使用 Github API v3 在单个调用中以递归方式遍历树,从而大大减少了请求数。你会有这样的东西:
async function getAllEntries(repo, owner){
return fetch(`https://api.github.com/repos/${owner}/${repo}/git/trees/master?recursive=1`,{
headers: {
'Authorization': `Bearer ${token}`,
}
})
.then(response => response.json());
}
完整示例(对于盖茨比源代码插件):
const { ApolloClient } = require("apollo-client")
const { InMemoryCache } = require("apollo-cache-inmemory")
const { HttpLink } = require("apollo-link-http")
const fetch = require("node-fetch")
const gql = require("graphql-tag")
const { setContext } = require('apollo-link-context');
const token = "YOUR_TOKEN";
const repository = "YOUR_REPO";
const owner = "YOUR_LOGIN";
const authLink = setContext((_, { headers }) => {
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : null,
}
}
});
const defaultOptions = {
watchQuery: {
fetchPolicy: 'no-cache',
errorPolicy: 'ignore',
},
query: {
fetchPolicy: 'no-cache',
errorPolicy: 'all',
},
}
const client = new ApolloClient({
link: authLink.concat(new HttpLink({ uri: 'https://api.github.com/graphql', fetch: fetch })),
cache: new InMemoryCache(),
defaultOptions: defaultOptions,
});
exports.sourceNodes = async function sourceNodes(
{
actions,
cache,
createContentDigest,
createNodeId,
getNodesByType,
getNode,
},
pluginOptions
) {
const { createNode, touchNode, deleteNode } = actions
const { tree } = await getAllEntries(repository, owner)
fileArr = []
tree.map(it => {
fileArr.push(walk(it, true))
});
let res = await Promise.all(fileArr)
let result = res.filter(value => Object.keys(value).length !== 0);
console.log(result);
console.log(`got ${result.length} results`);
return
}
async function walk(entry){
if (entry.type === "blob") {
let res = await getBlob(repository, entry.sha);
return {
name: entry.path,
oid: entry.sha,
data: res.data.viewer.repository.object.text
};
}
return {};
}
async function getAllEntries(repo, owner){
return fetch(`https://api.github.com/repos/${owner}/${repo}/git/trees/master?recursive=1`,{
headers: {
'Authorization': `Bearer ${token}`,
}
})
.then(response => response.json());
}
async function getBlob(repo, oid){
return await client.query({
query: gql`
query getFile($id: GitObjectID!) {
viewer {
repository(name: "${repo}") {
object(oid: $id) {
... on Blob {
text
}
}
}
}
}
`,
variables: {
id: oid
}
})
}
如果您需要不惜一切代价获取二进制内容,则需要使用Github API v3,它直接在获取树结果中提供内容URL。内容 URL 返回以 base64 编码的内容,请参阅此文件。
因此,如果您想要base64编码的内容(二进制+文本),您将拥有以下内容(对于源插件):gatsby-node.js
const fetch = require("node-fetch")
const token = "YOUR_TOKEN";
const repository = "YOUR_REPO";
const owner = "YOUR_LOGIN";
exports.sourceNodes = async function sourceNodes(
{
actions,
cache,
createContentDigest,
createNodeId,
getNodesByType,
getNode,
},
pluginOptions
) {
const { createNode, touchNode, deleteNode } = actions
const { tree } = await getAllEntries(repository, owner)
fileArr = []
tree.map(it => {
fileArr.push(walk(it, true))
});
let res = await Promise.all(fileArr)
console.log(res);
console.log(`got ${res.length} results`);
return
}
async function walk(entry){
if (entry.type === "blob") {
let res = await getBlob(entry.url);
return {
name: entry.path,
oid: entry.sha,
data: res.content
};
}
return {};
}
async function getAllEntries(repo, owner){
return fetch(`https://api.github.com/repos/${owner}/${repo}/git/trees/master?recursive=1`, {
headers: {
'Authorization': `Bearer ${token}`,
}
})
.then(response => response.json());
}
async function getBlob(url){
return fetch(url, {
headers: {
'Authorization': `Bearer ${token}`,
}
})
.then(response => response.json());
}

TA贡献1828条经验 获得超3个赞
首先,您可以遍历每棵树,然后为每个树获取一个文件数组,这将为您提供一个二维数组:
.map(async entry => {
const files = await getTree(entry);
return Promise.all(
files.map(file => getFile(file).then(fileRes => ({ data: fileRes.text })))
);
)
然后,您需要拼合结果,使其成为一个单维数组:
const files = allFiles.flat();
我希望我正确地理解了你的问题;结果是一个单维的文件数组(即 ),而不是一个多维数组(即 )。getTree()[file1, file2, file3][[file1, file2], [[file1, file2], [file1]], file1, file2]
添加回答
举报