mirror of git3://git3.w3q/git3-cli
commit
e750e5b2b0
@ -1,55 +1,58 @@
|
||||
{
|
||||
"name": "git3-cli",
|
||||
"version": "0.1.1",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": ">=14.16"
|
||||
},
|
||||
"bin": "dist/git3/index.js",
|
||||
"dependencies": {
|
||||
"@ethersproject/experimental": "^5.7.0",
|
||||
"axios": "^1.3.2",
|
||||
"bip39": "^3.0.4",
|
||||
"buffer-split": "^1.0.0",
|
||||
"colors-cli": "^1.0.29",
|
||||
"commander": "^10.0.0",
|
||||
"debug": "^4.3.4",
|
||||
"eth-ens-namehash": "^2.0.8",
|
||||
"ethers": "^5.7.2",
|
||||
"form-data": "^4.0.0",
|
||||
"git-config-path": "^2.0.0",
|
||||
"inquirer": "^9.1.4",
|
||||
"js-sha3": "^0.8.0",
|
||||
"parse-git-config": "^3.0.0",
|
||||
"rxjs": "^7.8.0",
|
||||
"rxjs-async-map": "^0.2.0",
|
||||
"rxjs-stream": "^5.0.0",
|
||||
"superpathjoin": "^2.0.1",
|
||||
"url-parse": "^1.5.10"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rm -rf ./dist ./bin",
|
||||
"build:git3": "esbuild src/git3/index.ts --bundle --platform=node --outfile=dist/git3.cjs --format=cjs",
|
||||
"build:git-remote": "esbuild src/git-remote-git3/index.ts --bundle --platform=node --outfile=dist/git-remote-git3.cjs --format=cjs",
|
||||
"build": "yarn clean && ( yarn build:git3 & yarn build:git-remote & wait)",
|
||||
"pkg:git3": "pkg dist/git3.cjs -c git3.pkg.json",
|
||||
"pkg:git-remote": "pkg dist/git-remote-git3.cjs -c git-remote-git3.pkg.json",
|
||||
"pkg:all": "yarn pkg:git3 && yarn pkg:git-remote",
|
||||
"pkg": "yarn build && yarn pkg:all",
|
||||
"install-mac": "yarn pkg && cp bin/git3-macos /usr/local/bin/git3 && cp bin/git-remote-git3-macos /usr/local/bin/git-remote-git3",
|
||||
"install-linux": "yarn pkg && cp bin/git3-linux /usr/local/bin/git3 && cp bin/git-remote-git3-linux /usr/local/bin/git-remote-git3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/buffer-split": "^1.0.0",
|
||||
"@types/debug": "^4.1.7",
|
||||
"@types/inquirer": "^9.0.3",
|
||||
"@types/node": "^18.11.18",
|
||||
"@types/parse-git-config": "^3.0.1",
|
||||
"@types/url-parse": "^1.4.8",
|
||||
"esbuild": "^0.17.0",
|
||||
"pkg": "^5.8.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^4.9.4"
|
||||
}
|
||||
"name": "git3-cli",
|
||||
"version": "0.1.1",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": ">=14.16"
|
||||
},
|
||||
"bin": "dist/git3/index.js",
|
||||
"dependencies": {
|
||||
"@ethersproject/experimental": "^5.7.0",
|
||||
"axios": "^1.3.2",
|
||||
"bip39": "^3.0.4",
|
||||
"buffer-split": "^1.0.0",
|
||||
"colors-cli": "^1.0.29",
|
||||
"commander": "^10.0.0",
|
||||
"debug": "^4.3.4",
|
||||
"eth-ens-namehash": "^2.0.8",
|
||||
"ethers": "^5.7.2",
|
||||
"form-data": "^4.0.0",
|
||||
"git-config-path": "^2.0.0",
|
||||
"inquirer": "^9.1.4",
|
||||
"js-sha3": "^0.8.0",
|
||||
"parse-git-config": "^3.0.0",
|
||||
"rxjs": "^7.8.0",
|
||||
"rxjs-async-map": "^0.2.0",
|
||||
"rxjs-stream": "^5.0.0",
|
||||
"superpathjoin": "^2.0.1",
|
||||
"url-parse": "^1.5.10"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rm -rf ./dist ./bin",
|
||||
"build:git3": "esbuild src/git3/index.ts --bundle --platform=node --outfile=dist/git3.cjs --format=cjs",
|
||||
"build:git-remote": "esbuild src/git-remote-git3/index.ts --bundle --platform=node --outfile=dist/git-remote-git3.cjs --format=cjs",
|
||||
"build": "yarn clean && ( yarn build:git3 & yarn build:git-remote & wait)",
|
||||
"pkg:git3": "pkg dist/git3.cjs -c git3.pkg.json",
|
||||
"pkg:git-remote": "pkg dist/git-remote-git3.cjs -c git-remote-git3.pkg.json",
|
||||
"pkg:all": "yarn pkg:git3 && yarn pkg:git-remote",
|
||||
"pkg": "yarn build && yarn pkg:all",
|
||||
"install-mac": "yarn pkg && cp bin/git3-macos /usr/local/bin/git3 && cp bin/git-remote-git3-macos /usr/local/bin/git-remote-git3",
|
||||
"install-linux": "yarn pkg && cp bin/git3-linux /usr/local/bin/git3 && cp bin/git-remote-git3-linux /usr/local/bin/git-remote-git3",
|
||||
"sync": "ts-node src/scripts/sync.ts",
|
||||
"clear-sync": "ts-node src/scripts/clear.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/buffer-split": "^1.0.0",
|
||||
"@types/debug": "^4.1.7",
|
||||
"@types/inquirer": "^9.0.3",
|
||||
"@types/node": "^18.11.18",
|
||||
"@types/parse-git-config": "^3.0.1",
|
||||
"@types/url-parse": "^1.4.8",
|
||||
"es-main": "^1.2.0",
|
||||
"esbuild": "^0.17.0",
|
||||
"pkg": "^5.8.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^4.9.4"
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,10 @@
|
||||
import { api, deleteHub } from "./sync.js"
|
||||
import fs from "fs"
|
||||
|
||||
fs.unlinkSync("./cache.json")
|
||||
|
||||
let res = await api.get("/orgs")
|
||||
for (const org of res.data) {
|
||||
console.log("hub:", org.name)
|
||||
deleteHub(org.name)
|
||||
}
|
@ -0,0 +1,276 @@
|
||||
import {
|
||||
FactoryProtocol,
|
||||
initFactoryByChainID,
|
||||
initNameService,
|
||||
parseGit3URI,
|
||||
} from "../common/git3-protocol.js"
|
||||
import network from "../config/evm-network.js"
|
||||
import { readFileSync, writeFileSync, existsSync } from "fs"
|
||||
import { ethers } from "ethers"
|
||||
import axios from "axios"
|
||||
import nameServices from "../config/name-services.js"
|
||||
import { Retrier } from "../common/queue-task.js"
|
||||
|
||||
let cache = loadCache()
|
||||
|
||||
export let api = axios.create({
|
||||
baseURL: `http://127.0.0.1:${process.env.port || 3331}/api/v1/`,
|
||||
responseType: "json",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `token ${process.env.TOKEN}`,
|
||||
},
|
||||
validateStatus: function (status) {
|
||||
return status < 500
|
||||
},
|
||||
})
|
||||
|
||||
function loadCache() {
|
||||
existsSync("./cache.json") || writeFileSync("./cache.json", "")
|
||||
let text = readFileSync("./cache.json").toString()
|
||||
if (text == "") {
|
||||
return {
|
||||
factory: {
|
||||
3334: {
|
||||
start: 5375112,
|
||||
last: 5375112,
|
||||
},
|
||||
421613: {
|
||||
start: 9341366,
|
||||
last: 9341366,
|
||||
},
|
||||
},
|
||||
hubs: {},
|
||||
ns: {
|
||||
start: 9340900,
|
||||
last: 9340900,
|
||||
nameHub: {},
|
||||
hubName: {},
|
||||
},
|
||||
}
|
||||
} else {
|
||||
return JSON.parse(text)
|
||||
}
|
||||
}
|
||||
|
||||
function saveCache(cache: any) {
|
||||
writeFileSync("./cache.json", JSON.stringify(cache))
|
||||
}
|
||||
const RANGE = 1000
|
||||
const WAIT_SECONDS = 10
|
||||
|
||||
async function eventIterator(
|
||||
contract: ethers.Contract,
|
||||
filters: any[],
|
||||
last: number,
|
||||
saveLastCallback: (_last: number) => void,
|
||||
eventCallback: (event: any) => void,
|
||||
stop: () => boolean = () => false
|
||||
) {
|
||||
let provider = contract.provider
|
||||
|
||||
while (true) {
|
||||
if (stop && stop()) break
|
||||
let lastBlock = await Retrier(async () => await provider.getBlockNumber(), { maxRetry: 10 })
|
||||
for (let i = last; i < lastBlock; i += RANGE) {
|
||||
let end = i + RANGE - 1
|
||||
if (end >= lastBlock) end = lastBlock - 1
|
||||
console.log(i, end)
|
||||
for (const filter of filters) {
|
||||
let events = await Retrier(async () => await contract.queryFilter(filter, i, end), {
|
||||
maxRetry: 10,
|
||||
})
|
||||
for (const event of events) {
|
||||
await eventCallback(event)
|
||||
//console.log(protocol.chainId, i, end, event.args, event)
|
||||
}
|
||||
}
|
||||
|
||||
last = end
|
||||
saveLastCallback(last)
|
||||
}
|
||||
await new Promise((resolve) => setTimeout(resolve, WAIT_SECONDS * 1000))
|
||||
}
|
||||
}
|
||||
|
||||
async function syncFactory(protocol: FactoryProtocol) {
|
||||
let factory = protocol.factory
|
||||
let last = cache.factory[protocol.chainId].last
|
||||
console.log("syncFactory", protocol.chainId, last)
|
||||
await eventIterator(
|
||||
factory,
|
||||
[factory.filters.CreateHub()],
|
||||
last,
|
||||
(_last) => {
|
||||
cache.factory[protocol.chainId].last = _last
|
||||
saveCache(cache)
|
||||
},
|
||||
async (event) => {
|
||||
let hubAddr = event.args!.hub
|
||||
if (cache.ns.hubName[hubAddr]) {
|
||||
hubAddr = cache.ns.hubName[hubAddr]
|
||||
} else {
|
||||
hubAddr = `${hubAddr}:${protocol.chainId}`
|
||||
}
|
||||
console.log("hub:", hubAddr, "block:", event.blockNumber)
|
||||
await createHub(hubAddr)
|
||||
syncHub(hubAddr, event.blockNumber)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function Hex0xToStr(hex0x: string) {
|
||||
return Buffer.from(hex0x.slice(2), "hex").toString()
|
||||
}
|
||||
|
||||
async function syncHub(hubAddr: string, start: number) {
|
||||
if (start > 0) {
|
||||
cache.hubs[hubAddr] = { start, last: start }
|
||||
}
|
||||
let protocol = await parseGit3URI(hubAddr, { skipRepoName: true, ignoreProtocolHeader: true })
|
||||
let hub = protocol.hub
|
||||
let last = cache.hubs[hubAddr].last
|
||||
|
||||
await eventIterator(
|
||||
hub,
|
||||
[hub.filters.RepoCreated(), hub.filters.SetRepoRef()],
|
||||
last,
|
||||
(_last) => {
|
||||
if (cache.hubs[hubAddr]) {
|
||||
cache.hubs[hubAddr].last = _last
|
||||
saveCache(cache)
|
||||
}
|
||||
},
|
||||
async (event) => {
|
||||
if (event.event == "RepoCreated") {
|
||||
let repoName = Hex0xToStr(event.args!.repoName)
|
||||
console.log("repo:", hubAddr, repoName)
|
||||
await mirrorRepo(hubAddr, repoName)
|
||||
} else if (event.event == "SetRepoRef") {
|
||||
let repoName = Hex0xToStr(event.args!.repoName)
|
||||
await pullRepo(hubAddr, repoName)
|
||||
}
|
||||
},
|
||||
() => {
|
||||
return !cache.hubs[hubAddr]
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
async function mirrorRepo(hubAddr: string, repoName: string) {
|
||||
let uri = `git3://${hubAddr}/${repoName}`
|
||||
let res = await api.post("/repos/migrate", {
|
||||
clone_addr: uri,
|
||||
mirror: true,
|
||||
mirror_interval: "1h",
|
||||
private: false,
|
||||
repo_name: repoName,
|
||||
repo_owner: hubAddr,
|
||||
service: "git",
|
||||
uid: 0,
|
||||
})
|
||||
console.log("mirrorRepo", uri, res.status)
|
||||
}
|
||||
|
||||
async function pullRepo(hubAddr: string, repoName: string) {
|
||||
let uri = `git3://${hubAddr}/${repoName}`
|
||||
let res = await api.post(`/repos/${hubAddr}/${repoName}/mirror-sync`)
|
||||
console.log("pullRepo", uri, res.status)
|
||||
}
|
||||
|
||||
async function migrateHub(oldHubAddr: string, newHubAddr: string) {
|
||||
console.log("migrateHub:", oldHubAddr, newHubAddr)
|
||||
let oldHub = cache.hubs[oldHubAddr]
|
||||
if (oldHub) {
|
||||
deleteHub(oldHubAddr)
|
||||
delete cache.hubs[oldHubAddr]
|
||||
await createHub(newHubAddr)
|
||||
syncHub(newHubAddr, oldHub.start)
|
||||
} else {
|
||||
await createHub(newHubAddr)
|
||||
}
|
||||
}
|
||||
|
||||
async function syncNameService() {
|
||||
let nsContract = initNameService()
|
||||
let last = cache.ns.last
|
||||
|
||||
await eventIterator(
|
||||
nsContract,
|
||||
[nsContract.filters.RegisterHub()],
|
||||
last,
|
||||
(_last) => {
|
||||
cache.ns.last = _last
|
||||
saveCache(cache)
|
||||
},
|
||||
async (event) => {
|
||||
let name = event.args!.name
|
||||
let hub = event.args!.hub
|
||||
let [_, nsDomain] = name.split(".")
|
||||
let ns = nameServices[nsDomain]
|
||||
let hubAddr = `${hub}:${ns.chainId}`
|
||||
let old = cache.ns.nameHub[name]
|
||||
if (!old) {
|
||||
await migrateHub(hubAddr, name)
|
||||
} else {
|
||||
if (old != hub) {
|
||||
// Rebind NS hub address
|
||||
delete cache.ns.hubName[old]
|
||||
await migrateHub(name, name)
|
||||
} else {
|
||||
// same name, do nothing
|
||||
}
|
||||
}
|
||||
console.log("ns:", name, hub)
|
||||
cache.ns.nameHub[name] = hub
|
||||
cache.ns.hubName[hub] = name
|
||||
saveCache(cache)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
export async function deleteHub(hubAddr: string): Promise<boolean> {
|
||||
let res = await api.get(`/orgs/${hubAddr}/repos`, { params: { page: 1, limit: 100000 } })
|
||||
if (res.status != 200) {
|
||||
return false
|
||||
}
|
||||
for (const repo of res.data) {
|
||||
res = await api.delete(`/repos/${hubAddr}/${repo.name}`)
|
||||
console.log("delete repo:", `${hubAddr}/${repo.name}`)
|
||||
}
|
||||
res = await api.delete(`/orgs/${hubAddr}`)
|
||||
console.log(res.status, res.data)
|
||||
return res.status == 200
|
||||
}
|
||||
|
||||
async function createHub(hubAddr: string) {
|
||||
let res = await api.post(`/orgs`, {
|
||||
repo_admin_change_team_access: true,
|
||||
username: hubAddr,
|
||||
visibility: "public",
|
||||
})
|
||||
if (res.status != 201) {
|
||||
console.log("[ERROR] createHub", hubAddr, res.status, res.data)
|
||||
}
|
||||
return res.status == 201
|
||||
}
|
||||
|
||||
async function main() {
|
||||
let tasks = []
|
||||
tasks.push(syncNameService())
|
||||
|
||||
for (const [chainId, _] of Object.entries(network)) {
|
||||
let protocol = await initFactoryByChainID(chainId, null)
|
||||
tasks.push(syncFactory(protocol))
|
||||
}
|
||||
|
||||
for (const [hubAddr, _] of Object.entries(cache.hubs)) {
|
||||
tasks.push(syncHub(hubAddr, 0))
|
||||
}
|
||||
|
||||
await Promise.all(tasks)
|
||||
}
|
||||
import esMain from "es-main"
|
||||
if (esMain(import.meta)) {
|
||||
main()
|
||||
}
|
Loading…
Reference in new issue