diff --git a/admin/README.md b/admin/README.md deleted file mode 100644 index b9980184c..000000000 --- a/admin/README.md +++ /dev/null @@ -1,59 +0,0 @@ -Admin Tool -========== - -This tool is meant for admin tasks related to ethers.js. - - -Workflow --------- - -After a new series of changes have been made and tested: - -1. Run `npm run update-versions` to update and build all packages -2. Make any human-necessary changes to the automatically updated `CHANGELOG.md` -3. Run `git add .` -4. Run `git commit -S -m "Updated dist files."` -5. Run `git push` -6. Wait for TravisCI to complete running test cases -7. Run `npm run publish-all` to publish changed packages to NPM and tag GitHub - - -Update Dependency Graph: admin/cmds/update-depgraph ---------------------------------------------------- - -This is run as part of `npm run bootstrap` before running lerna bootstrap. -It recomputes the dependency graph and writes out the ordered -**tsconfig.project.json** - - -Update Versions: admin/cmds/update-versions -------------------------------------------- - -Run using the `npm run update-versions`, which also cleans, bootstraps and -rebuilds the project before running the script. - -For each package that has changed from the version in NPM (the published -tarballs are compared): - -- Update the `version` in the **package.json** -- Update the `src.ts/_version.ts` (matches the **package.json**) -- Updates the `tarballHash` in the **package.json** -- Compiles the TypeScript (which updates the `_version.js` and `_version.d.js`) -- Lists all changed files (highlighting src.ts files) - -Then: - -- Generate the distribution files -- Update the `CHANGELOG.md` - - -Publish: admin/cmds/publish ---------------------------- - -Run using `npm run publish-all`. This requires a password for the secure -local config and the OTP for NPM. - -- Publish (in dependency order) changed files to NPM -- The `gitHead` is updated in **only** the NPM **package.json** -- @TODO: Cut a release on GitHub including the relevant CHANGELOG entry - diff --git a/admin/build.js b/admin/build.js deleted file mode 100644 index 3389eadab..000000000 --- a/admin/build.js +++ /dev/null @@ -1,111 +0,0 @@ -"use strict"; - -const fs = require("fs"); -const resolve = require("path").resolve; -const spawn = require("child_process").spawn; - -const { dirnames } = require("./local"); -const { loadPackage, savePackage } = require("./local"); -const { loadJson, saveJson } = require("./utils"); - -function run(progname, args, ignoreErrorStream) { - return new Promise((resolve, reject) => { - const proc = spawn(progname, args); - - let stdout = Buffer.from([]); - let stderr = Buffer.from([]); - - proc.stdout.on("data", (data) => { - stdout = Buffer.concat([ stdout, data ]); - }); - - proc.stderr.on("data", (data) => { - stderr = Buffer.concat([ stdout, data ]); - }); - - proc.on("error", (error) => { - console.log("ERROR"); - console.log(stderr.toString()); - error.stderr = stderr.toString(); - error.stdout = stdout.toString(); - reject(error); - }); - - proc.on("close", (code) => { - if ((stderr.length && !ignoreErrorStream) || code !== 0) { - console.log("ERROR"); - console.log(stderr.toString()); - - let error = new Error(`stderr not empty: ${ progname } ${ JSON.stringify(args) }`); - error.stderr = stderr.toString(); - error.stdout = stdout.toString(); - error.statusCode = code; - reject(error); - } else { - resolve(stdout.toString()); - } - }); - }); -} - -function setupConfig(outDir, moduleType, targetType) { - - // Configure the tsconfit.package.json... - const path = resolve(__dirname, "../tsconfig.package.json"); - const content = loadJson(path); - content.compilerOptions.module = moduleType; - content.compilerOptions.target = targetType; - saveJson(path, content); - - // Configure the browser field for every pacakge, copying the - // browser.umd filed for UMD and browser.esm for ESM - dirnames.forEach((dirname) => { - let info = loadPackage(dirname); - - if (info._ethers_nobuild) { return; } - - if (targetType === "es2015") { - if (info["browser.esm"]) { - info.browser = info["browser.esm"]; - } - } else if (targetType === "es5") { - if (info["browser.umd"]) { - info.browser = info["browser.umd"]; - } - } else { - throw new Error("unsupported target"); - } - savePackage(dirname, info); - - let path = resolve(__dirname, "../packages", dirname, "tsconfig.json"); - let content = loadJson(path); - content.compilerOptions.outDir = outDir; - saveJson(path, content); - }); -} - -function setupBuild(buildModule) { - if (buildModule) { - setupConfig("./lib.esm/", "es2015", "es2015"); - } else { - setupConfig("./lib/", "commonjs", "es5"); - } -} - -function runBuild(buildModule) { - setupBuild(buildModule); - - // Compile - return run("npx", [ "tsc", "--build", resolve(__dirname, "../tsconfig.project.json"), "--force" ]); -} - -function runDist() { - return run("npm", [ "run", "_dist" ], true); -} - -module.exports = { - run: run, - runDist: runDist, - runBuild: runBuild, - setupBuild: setupBuild -}; diff --git a/admin/changelog.js b/admin/changelog.js deleted file mode 100644 index eaa5e89c7..000000000 --- a/admin/changelog.js +++ /dev/null @@ -1,145 +0,0 @@ -"use strict"; - -const fs = require("fs"); -const resolve = require("path").resolve; - -const git = require("./git"); -const local = require("./local"); -const npm = require("./npm"); -const utils = require("./utils"); - -const ChangelogPath = resolve(__dirname, "../CHANGELOG.md"); - -async function generate() { - - // Get each section of the Changelog - let existing = fs.readFileSync(ChangelogPath).toString().split("\n"); - let sections = [ ]; - let lastLine = existing[0]; - existing.slice(1).forEach((line) => { - if (line.substring(0, 5) === "=====" || line.substring(0, 5) === "-----") { - sections.push({ - title: lastLine, - underline: line.substring(0, 1), - body: [ ] - }); - lastLine = null; - return; - } else if (lastLine) { - sections[sections.length - 1].body.push(lastLine); - } - lastLine = line; - }); - sections[sections.length - 1].body.push(lastLine); - - let lastVersion = await npm.getPackageVersion("ethers"); - - let logs = await git.run([ "log", (lastVersion.gitHead + "..") ]); - - let changes = [ ]; - logs.split("\n").forEach((line) => { - if (line.toLowerCase().substring(0, 6) === "commit") { - changes.push({ - commit: line.substring(6).trim(), - body: [ ] - }); - } else if (line.toLowerCase().substring(0, 5) === "date:") { - changes[changes.length - 1].date = utils.getDateTime(new Date(line.substring(5).trim())); - } else if (line.substring(0, 1) === " ") { - line = line.trim(); - if (line === "") { return; } - changes[changes.length - 1].body += line + " "; - } - }); - - // @TODO: - // ethers/version ([date](tag)) - let newSection = { - title: `ethers/v${ local.loadPackage("ethers").version } (${utils.getDateTime(new Date())})`, - underline: "-", - body: [ ] - } - - // Delete duplicate sections for the same version (ran update multiple times) - while (sections[1].title === newSection.title) { - sections.splice(1, 1); - } - - changes.forEach((change) => { - let body = change.body.trim(); - let link = body.match(/(\((.*#.*)\))/) - let commit = `[${ change.commit.substring(0, 7) }](https://github.com/ethers-io/ethers.js/commit/${ change.commit })`; - if (link) { - body = body.replace(/ *(\(.*#.*)\) */, ""); - link = link[2].replace(/#([0-9]+)/g, (all, issue) => { - return `[#${ issue }](https://github.com/ethers-io/ethers.js/issues/${ issue })`; - }) + "; " + commit; - } else { - link = commit; - } - newSection.body.push(` - ${ body } (${ link })`); - }); - - sections.splice(1, 0, newSection); - - - let formatted = [ ]; - sections.forEach((section) => { - formatted.push(section.title); - formatted.push(utils.repeat(section.underline, section.title.length)); - formatted.push(""); - section.body.forEach((line) => { - line = line.trim(); - if (line === "") { return; } - if (line.substring(0, 1) === "-") { - line = "- " + line.substring(1).trim(); - } - if (section.underline === "-") { - line = " " + line; - } - formatted.push(line); - }); - formatted.push(""); - }); - - return formatted.join("\n") + "\n"; -} - -function getChanges() { - const changes = [ ]; - - let lastLine = null; - fs.readFileSync(ChangelogPath).toString().split("\n").forEach((line) => { - line = line.trim(); - if (line === "") { return; } - - if (line.substring(0, 5) === "-----") { - changes.push({ title: lastLine, lines: [ ] }); - } else if (line.substring(0, 1) === "-" && changes.length) { - changes[changes.length - 1].lines.push(line); - } - lastLine = line; - }); - - return changes; -} - -function latestChange() { - const recent = getChanges()[0]; - - const match = recent.title.match(/ethers\/([^\(]*)\(([^\)]*)\)/); - - return { - title: recent.title, - version: match[1].trim(), - data: match[2].trim(), - content: recent.lines.join("\n") - }; -} - -module.exports = { - generate: generate, - latestChange: latestChange, - ChangelogPath: ChangelogPath, -} - diff --git a/admin/cmds/cache-github.js b/admin/cmds/cache-github.js deleted file mode 100644 index 8f9ef5297..000000000 --- a/admin/cmds/cache-github.js +++ /dev/null @@ -1,10 +0,0 @@ -"use strict"; - -const config = require("../config"); -const { syncIssues } = require("../github"); - -(async function() { - const user = await config.get("github-user"); - const password = await config.get("github-readonly"); - await syncIssues(user, password); -})(); diff --git a/admin/cmds/grep-github.js b/admin/cmds/grep-github.js deleted file mode 100644 index 39c4b8590..000000000 --- a/admin/cmds/grep-github.js +++ /dev/null @@ -1,142 +0,0 @@ -"use strict"; - -const { colorify } = require("../log"); -const { getIssues } = require("../github"); -const { repeat } = require("../utils"); - -const Options = { - "body": 1, - "end": 1, - "issue": 1, - "start": 1, - "title": 1, - "user": 1, -}; - -const Flags = { - "open": 1, - "match-case": 1, -}; - -(async function() { - const options = { }; - for (let i = 2; i < process.argv.length; i++) { - const option = process.argv[i]; - if (option.substring(0, 2) === "--") { - const comps = option.substring(2).split(/=/); - if (Flags[comps[0]]) { - if (comps[1] != null) { throw new Error("Invalid flag: " + option); } - options[comps[0]] = true; - } else if (Options[comps[0]]) { - if (comps[1] == null) { - options[comps[0]] = process.argv[++i]; - if (options[comps[0]] == null) { - throw new Error("Missing option value: " + option); - } - } else { - options[comps[0]] = comps[1]; - } - } else { - throw new Error("Unexpected option: " + option); - } - } else { - throw new Error("Unexpected argument: " + option); - } - } - - if (options["title"]) { options.title = new RegExp(options.title, (options["match-case"] ? "": "i")); } - if (options["body"]) { options.body = new RegExp(options.title, (options["match-case"] ? "": "i")); } - if (options["start"]) { - if (options["start"].match(/^[0-9]{4}-[0-9]{2}-[0-9{2}]$/)) { - throw new Error("Expected YYYY-MM-DD"); - } - } - if (options["end"]) { - if (options["end"].match(/^[0-9]{4}-[0-9]{2}-[0-9{2}]$/)) { - throw new Error("Expected YYYY-MM-DD"); - } - } - - const count = { issues: 0, comments: 0, code: 0, responses: 0 }; - - const issues = await getIssues(); - issues.forEach((issue) => { - const info = issue.issue; - const comments = issue.comments; - - if (options.issue && parseInt(options.issue) != info.number) { return; } - if (options.open && info.state !== "open") { return; } - if (options.title && !info.title.match(options.title)) { return; } - if (options.body) { - const body = info.body + "\n" + comments.map((c) => (c.body)).join("\n"); - if (!body.match(options.body)) { - return; - } - } - if (options.user) { - const users = comments.map((c) => (c.user.login)); - users.push(info.user.login); - if (users.indexOf(options.user) === -1) { - return; - } - } - - const dates = comments.map((c) => (c.created_at.split("T")[0])); - dates.push(info.created_at.split("T")[0]); - - if (options.start) { - if (dates.filter((d) => (d >= options.start)).length === 0) { return; } - } - if (options.end) { - if (dates.filter((d) => (d <= options.start)).length === 0) { return; } - } - - count.issues++; - - console.log(colorify(repeat("=", 70), "bold")) - console.log(colorify("Issue:", "bold"), info.title, ` (#${ info.number })`); - console.log(colorify("User:","bold"), colorify(info.user.login, "blue")); - console.log(colorify("State:", "bold"), info.state); - if (info.created_at === info.updated_at) { - console.log(colorify("Created:", "bold"), info.created_at); - } else { - console.log(colorify("Created:", "bold"), info.created_at, ` (updated: ${ info.updated_at })`); - } - info.body.trim().split("\n").forEach((line) => { - console.log(" " + line); - }); - - if (comments.length) { - comments.forEach((info) => { - if (options.start && info.created_at < options.start) { return ; } - if (options.end && info.created_at > options.end) { return; } - count.comments++; - if (options.user && info.user.login !== options.user) { return; } - count.responses++; - if (info.body.indexOf("`") >= 0) { count.code++; } - console.log(colorify(repeat("-", 70), "bold")); - console.log(colorify("User:", "bold"), colorify(info.user.login, "green")); - if (info.created_at === info.updated_at) { - console.log(colorify("Created:", "bold"), info.created_at); - } else { - console.log(colorify("Created:", "bold"), info.created_at, ` (updated: ${ info.updated_at })`); - } - info.body.trim().split("\n").forEach((line) => { - console.log(" " + line); - }); - }); - } - }); - - console.log(colorify(repeat("=", 70), "bold")) - - // @TODO: Add stats on new/closed issues - //if (options.user) { - // console.log(`${ count.responses } responses (${ count.code } w/ code) on ${ count.comments } comments across ${ count.issues } issues.`); - //} else { - console.log(`${ count.comments } comment${ (count.comments !== 1) ? "s": "" } across ${ count.issues } issue${ (count.issues !== 1) ? "s": ""}.`); - //} - -})().catch((error) => { - console.log("Error: " + error.message); -}); diff --git a/admin/cmds/lock-versions.js b/admin/cmds/lock-versions.js deleted file mode 100644 index 8b5431a5a..000000000 --- a/admin/cmds/lock-versions.js +++ /dev/null @@ -1,49 +0,0 @@ -"use strict"; - -const { getOrdered, loadPackage } = require("../depgraph"); -const { savePackage } = require("../local"); -const { log } = require("../log"); - -(async function() { - let versions = { }; - - const dirnames = getOrdered(); - - dirnames.forEach((dirname) => { - let info = loadPackage(dirname); - if (info.name.split("/")[0] === "@ethersproject" || info.name === "ethers") { - versions[info.name] = info.version; - } - }); - - dirnames.forEach((dirname) => { - const info = loadPackage(dirname); - let shown = false; - ["dependencies", "devDependencies"].forEach((key) => { - const deps = info[key]; - if (!deps) { return; } - Object.keys(deps).forEach((name) => { - // Not a package in this monorepoa - const version = versions[name]; - if (version == null) { return; } - - const value = ((version.indexOf("beta") !== -1) ? ">=": "^") + version; - - // No change - if (value === deps[name]) { return; } - - // Show a header for the first change - if (!shown) { - log(``); - shown = true; - } - - // Show the locked version - log(` : ${ deps[name] } => ", ">") }>`); - deps[name] = value; - }); - }); - savePackage(dirname, info); - }); - -})(); diff --git a/admin/cmds/publish.js b/admin/cmds/publish.js deleted file mode 100644 index 845d1fb0b..000000000 --- a/admin/cmds/publish.js +++ /dev/null @@ -1,210 +0,0 @@ -"use strict"; - -const { basename, resolve } = require("path"); -const fs = require("fs"); - -const AWS = require('aws-sdk'); - -const config = require("../config"); - -const { ChangelogPath, latestChange } = require("../changelog"); -const { getOrdered, loadPackage } = require("../depgraph"); -const { getGitTag } = require("../git"); -const { createRelease } = require("../github"); -const { getPackageVersion, publish } = require("../npm"); -const { log } = require("../log"); - -const USER_AGENT = "ethers-dist@0.0.0"; -const TAG = "latest"; - - -let dirnames = getOrdered(); - -// Only publish specific packages -if (process.argv.length > 2) { - let filter = process.argv.slice(2); - - // Verify all named packages exist - filter.forEach((dirname) => { - try { - loadPackage(dirname); - } catch (error) { - console.log("Package not found: " + dirname); - process.exit(1); - } - }); - - // Filter out pacakges we don't care about - dirnames = dirnames.filter((dirname) => (filter.indexOf(dirname) >= 0)); -} - - -function putObject(s3, info) { - return new Promise(function(resolve, reject) { - s3.putObject(info, function(error, data) { - if (error) { - reject(error); - } else { - resolve({ - name: info.Key, - hash: data.ETag.replace(/"/g, '') - }); - } - }); - }); -} - -function invalidate(cloudfront, distributionId) { - return new Promise((resolve, reject) => { - cloudfront.createInvalidation({ - DistributionId: distributionId, - InvalidationBatch: { - CallerReference: `${ USER_AGENT }-${ parseInt(((new Date()).getTime()) / 1000) }`, - Paths: { - Quantity: "1", - Items: [ - "/\*" - ] - } - } - }, function(error, data) { - if (error) { - console.log(error); - return; - } - resolve(data.Invalidation.Id); - }); - }); -} - -(async function() { - let token = null; - - const gitCommit = await getGitTag(ChangelogPath); - - let includeEthers = false; - - // @TODO: Fail if there are any untracked files or unchecked in files - - // Load the token from the encrypted store - try { - token = await config.get("npm-token"); - } catch (error) { - switch (error.message) { - case "wrong password": - log(""); - break; - case "cancelled": - break; - default: - console.log(error); - } - - log(""); - - return; - } - - token = token.trim().split("="); - - let options = { - npmVersion: USER_AGENT, - tag: TAG - }; - - // Set the authentication token - options[token[0]] = token[1]; - - for (let i = 0; i < dirnames.length; i++) { - let dirname = dirnames[i]; - - if (dirname === "ethers") { - includeEthers = true; - } - - let info = loadPackage(dirname); - let npmInfo = await getPackageVersion(info.name); - if (!npmInfo) { npmInfo = { version: "NEW" }; } - - if (info.tarballHash === npmInfo.tarballHash) { continue; } - - log(` ${info.name}...`); - log(` ${npmInfo.version} > ${info.version}`); - - let success = await publish(dirname, options); - if (!success) { - log(" "); - return; - } - log(" "); - } - - // Publish the GitHub release - const beta = false; - if (includeEthers) { - - // Get the latest change from the changelog - const change = latestChange(); - - // Publish the release to GitHub - { - // The password above already succeeded - const username = await config.get("github-user"); - const password = await config.get("github-release"); - - - // Publish the release - const link = await createRelease(username, password, change.version, change.title, change.content, beta, gitCommit); - log(` ${ link }`); - } - - // Upload the scripts to the CDN and refresh the edge caches - { - const awsAccessId = await config.get("aws-upload-scripts-accesskey"); - const awsSecretKey = await config.get("aws-upload-scripts-secretkey"); - const bucketName = await config.get("aws-upload-scripts-bucket"); - const originRoot = await config.get("aws-upload-scripts-root"); - const distributionId = await config.get("aws-upload-scripts-distribution-id"); - - const s3 = new AWS.S3({ - apiVersion: '2006-03-01', - accessKeyId: awsAccessId, - secretAccessKey: awsSecretKey - }); - - // Upload the libs to ethers-v5.0 and ethers-5.0.x - const fileInfos = [ - { filename: "packages/ethers/dist/ethers.esm.min.js", key: `ethers-${ change.version.substring(1) }.esm.min.js` }, - { filename: "packages/ethers/dist/ethers.umd.min.js", key: `ethers-${ change.version.substring(1) }.umd.min.js` }, - { filename: "packages/ethers/dist/ethers.esm.min.js", key: `ethers-5.0.esm.min.js` }, - { filename: "packages/ethers/dist/ethers.umd.min.js", key: `ethers-5.0.umd.min.js` }, - ]; - - for (let i = 0; i < fileInfos.length; i++) { - const fileInfo = fileInfos[i]; - const status = await putObject(s3, { - ACL: 'public-read', - Body: fs.readFileSync(resolve(__dirname, "../../", fileInfo.filename)), - Bucket: bucketName, - ContentType: "application/javascript; charset=utf-8", - Key: (originRoot + fileInfo.key) - }); - - log(` https://cdn.ethers.io/lib/${ fileInfo.key }`); - } - - // Flush the edge caches - { - const cloudfront = new AWS.CloudFront({ - //apiVersion: '2006-03-01', - accessKeyId: awsAccessId, - secretAccessKey: awsSecretKey - }); - - const invalidationId = await invalidate(cloudfront, distributionId); - log(` ${ invalidationId }`); - } - } - } - -})(); diff --git a/admin/cmds/serve-docs.js b/admin/cmds/serve-docs.js deleted file mode 100644 index 2920f0a80..000000000 --- a/admin/cmds/serve-docs.js +++ /dev/null @@ -1,100 +0,0 @@ -const fs = require("fs"); -const http = require("http"); -const path = require("path"); - -function getMime(filename) { - const comps = filename.split('.'); - const ext = comps[comps.length - 1]; - switch (ext.toLowerCase()) { - case 'css': return 'text/css'; - case 'doctree': return 'application/x-doctree'; - case 'eot': return 'application/vnd.ms-fontobject'; - case 'gif': return 'image/gif'; - case 'html': return 'text/html'; - case 'js': return 'application/javascript'; - case 'jpg': return 'image/jpeg'; - case 'jpeg': return 'image/jpeg'; - case 'md': return 'text/markdown'; - case 'pickle': return 'application/x-pickle'; - case 'png': return 'image/png'; - case 'svg': return 'image/svg+xml'; - case 'ttf': return 'application/x-font-ttf'; - case 'txt': return 'text/plain'; - case 'woff': return 'application/font-woff'; - } - console.log('NO MIME', filename); - return undefined; -} - -function start(root, options) { - if (root == null) { throw new Error("root required"); } - if (options == null) { options = { }; } - if (options.port == null) { options.port = 8000; } - root = path.resolve(root); - - const server = http.createServer((req, resp) => { - - // Follow redirects in options - if (options.redirects && options.redirects[req.url]) { - resp.writeHead(301, { Location: options.redirects[req.url] }); - resp.end(); - return; - } - - let filename = path.resolve(root, "." + req.url); - - // Make sure we aren't crawling out of our sandbox - if (req.url[0] !== "/" || filename.substring(0, filename.length) !== filename) { - resp.writeHead(403); - resp.end(); - return; - } - - try { - const stat = fs.statSync(filename); - if (stat.isDirectory()) { - - // Redirect bare directory to its path (i.e. "/foo" => "/foo/") - if (req.url[req.url.length - 1] !== "/") { - resp.writeHead(301, { Location: req.url + "/" }); - resp.end(); - return; - } - - filename += "/index.html"; - } - - const content = fs.readFileSync(filename); - - resp.writeHead(200, { - "Content-Length": content.length, - "Content-Type": getMime(filename) - }); - resp.end(content); - return; - - } catch (error) { - if (error.code === "ENOENT") { - resp.writeHead(404, { }); - resp.end(); - return; - } - - resp.writeHead(500, { }); - resp.end(); - return; - } - }); - - server.listen(options.port, () => { - console.log(`Server running on: http://localhost:${ options.port }`); - }); - - return server; -} - -start(path.resolve(__dirname, "../../docs"), { - redirects: { - "/": "/v5/" - } -}); diff --git a/admin/cmds/set-config.js b/admin/cmds/set-config.js deleted file mode 100644 index 07b599959..000000000 --- a/admin/cmds/set-config.js +++ /dev/null @@ -1,16 +0,0 @@ -"use strict"; - -const { prompt } = require("../../packages/cli"); -const config = require("../config"); - -if (process.argv.length !== 3) { - console.log("Usage: set-config KEY"); - process.exit(1); -} - -const key = process.argv[2]; - -(async function() { - const value = await prompt.getPassword("Value: "); - await config.set(key, value); -})(); diff --git a/admin/cmds/update-versions.js b/admin/cmds/update-versions.js deleted file mode 100644 index 3c487d9ef..000000000 --- a/admin/cmds/update-versions.js +++ /dev/null @@ -1,146 +0,0 @@ -"use strict"; - -// Expected this to be run after -// - npm run clean -// - npm run bootstrap -// - npm run build - -const fs = require("fs"); - -const semver = require("semver"); - -const { runBuild, runDist } = require("../build"); -const { ChangelogPath, generate } = require("../changelog"); -const { getOrdered, loadPackage } = require("../depgraph"); -const { getDiff, getStatus, getGitTag } = require("../git"); -const { updatePackage } = require("../local"); -const { getPackageVersion } = require("../npm"); -const { resolve } = require("../utils"); -const { colorify, log } = require("../log"); - -const { prompt } = require("../../packages/cli"); - -let dirnames = getOrdered(); - -// Only publish specific packages -if (process.argv.length > 2) { - let filter = process.argv.slice(2); - - // Verify all named packages exist - filter.forEach((dirname) => { - try { - loadPackage(dirname); - } catch (error) { - console.log("Package not found: " + dirname); - process.exit(1); - } - }); - - // Filter out pacakges we don't care about - dirnames = dirnames.filter((dirname) => (filter.indexOf(dirname) >= 0)); -} - -(async function() { - let progress = prompt.getProgressBar(colorify("Updating versions", "bold")); - - for (let i = 0; i < dirnames.length; i++) { - progress(i / dirnames.length); - - let dirname = dirnames[i]; - let path = resolve("packages", dirname); - - // Get local package.json (update the tarballHash) - let info = await updatePackage(dirname); - - // Get the remote package.json (or sub in a placeholder for new pacakges) - let npmInfo = await getPackageVersion(info.name); - if (!npmInfo) { npmInfo = { version: "NEW" }; } - - if (info.tarballHash === npmInfo.tarballHash) { continue; } - - // Bump the version if necessary - if (info.version === npmInfo.version) { - let newVersion = semver.inc(info.version, "patch"); - - // Write out the _version.ts - if (!info._ethers_nobuild) { - let code = "export const version = " + JSON.stringify(dirname + "/" + newVersion) + ";\n"; - fs.writeFileSync(resolve(path, "src.ts/_version.ts"), code); - } - - // Update the package.json (we do this after _version, so if we fail, - // this remains old; which is what triggers the version bump) - info = await updatePackage(dirname, { version: newVersion }); - } - } - progress(1); - - try { - log(""); - await runBuild(true); - log(""); - await runBuild(false); - log(""); - let content = await runDist(); - console.log(content); - } catch (error) { - console.log(error); - log(""); - return; - } - - // Update the tarball hash now that _version and package.json may have changed. - progress = prompt.getProgressBar(colorify("Updating tarballHash", "bold")); - for (let i = 0; i < dirnames.length; i++) { - progress(i / dirnames.length); - await updatePackage(dirnames[i]); - } - progress(1); - - // Show the changed files (compared to npm) - for (let i = 0; i < dirnames.length; i++) { - let dirname = dirnames[i]; - - // Get local package.json - let info = await loadPackage(dirname); - let path = resolve("packages/", dirname); - - // Get the remote package.json (or sub in a placeholder for new pacakges) - let npmInfo = await getPackageVersion(info.name); - if (!npmInfo) { npmInfo = { version: "NEW" }; } - - // No change - if (info.tarballHash === npmInfo.tarballHash) { continue; } - - let gitHead = await getGitTag(path); - - log(`: ${info.name}`); - log(` (bumping version)`); - log(` ${npmInfo.version} => ${info.version}`) - log(` `); - let filenames = await getDiff(path, npmInfo.gitHead, true); - filenames.forEach((filename) => { - let short = filename.split("/").slice(1).join("/"); - if (short.indexOf("/src.ts/") >= 0 || short.indexOf("/dist/") >= 0) { - log(` `); - } else { - log(` ${short}`); - } - }); - log(""); - } - - let existing = fs.readFileSync(ChangelogPath).toString(); - let changelog = await generate(); - if (existing !== changelog) { - let changelogStatus = await getStatus(ChangelogPath); - if (changelogStatus !== "unmodified") { - log(" There are local changes to the CHANGELOG (they will be discarded)"); - console.log(existing); - } - log("..."); - fs.writeFileSync(ChangelogPath, changelog); - } - - -})(); diff --git a/admin/cmds/upload-docs.js b/admin/cmds/upload-docs.js deleted file mode 100644 index 3bcd3dc27..000000000 --- a/admin/cmds/upload-docs.js +++ /dev/null @@ -1,181 +0,0 @@ -"use strict"; - -const crypto = require('crypto'); -const fs = require('fs'); -const path = require('path'); -const AWS = require('aws-sdk'); - -const config = require("../config"); - - -const Bucket = "docs.ethers.io"; - - -function _getKeys(s3, result, nextToken, callback) { - const params = { - Bucket: Bucket, - MaxKeys: 1000, - ContinuationToken: nextToken, - }; - s3.listObjectsV2(params, function(error, data) { - if (error) { - console.log(error); - callback(error); - return; - } - data.Contents.forEach(function(item) { - result[item.Key] = item.ETag.replace(/"/g,''); - }); - callback(null, data.IsTruncated ? data.NextContinuationToken: null); - }); -} - -function getKeys(s3) { - const result = {}; - return new Promise(function(resolve, reject) { - function handleBlock(error, nextToken) { - if (error) { - reject(error); - } else if (nextToken) { - nextBlock(nextToken); - } else { - resolve(result); - } - } - function nextBlock(nextToken) { - _getKeys(s3, result, nextToken, handleBlock); - } - nextBlock(undefined); - }); -} - -function getMime(filename) { - const comps = filename.split('.'); - const ext = comps[comps.length - 1]; - switch (ext.toLowerCase()) { - case 'css': return 'text/css'; - case 'doctree': return 'application/x-doctree'; - case 'eot': return 'application/vnd.ms-fontobject'; - case 'gif': return 'image/gif'; - case 'html': return 'text/html'; - case 'js': return 'application/javascript'; - case 'jpg': return 'image/jpeg'; - case 'jpeg': return 'image/jpeg'; - case 'json': return 'application/json'; - case 'md': return 'text/markdown'; - case 'pickle': return 'application/x-pickle'; - case 'png': return 'image/png'; - case 'svg': return 'image/svg+xml'; - case 'ttf': return 'application/x-font-ttf'; - case 'txt': return 'text/plain'; - case 'woff': return 'application/font-woff'; - } - console.log('NO MIME', filename); - return undefined; -} - -function putObject(s3, name, content) { - return new Promise(function(resolve, reject) { - s3.putObject({ - ACL: 'public-read', - Body: content, - Bucket: Bucket, - ContentType: getMime(name), - Key: name - }, function(error, data) { - if (error) { - reject(error); - } else { - console.log(" Done.") - resolve({ - name: name, - hash: data.ETag.replace(/"/g, '') - }); - } - }); - }); -} - -function hash(filename) { - const hasher = crypto.createHash('md5'); - hasher.update(fs.readFileSync(filename)); - return hasher.digest().toString('hex'); -} - -function _getFiles(result, root) { - fs.readdirSync(root).forEach(function(filename) { - - // We don't need to upload junk - if (filename === '.DS_Store') { return; } - - const fullFilename = path.join(root, filename) - const stat = fs.statSync(fullFilename); - if (stat.isDirectory()) { - _getFiles(result, fullFilename); - } else { - result[fullFilename] = hash(fullFilename); - } - }); -} - -function getFiles(basedir) { - // Make sure we have a trailing slash - if (!basedir.match(/\/$/)) { basedir += "/"; } - - // Fetch all the file hashes - const hashes = { }; - _getFiles(hashes, basedir); - - return Object.keys(hashes).reduce((accum, key) => { - accum[key.substring(basedir.length)] = hashes[key]; - return accum; - }, { }); -} - -(async function() { - const awsAccessId = await config.get("aws-upload-docs-accesskey"); - const awsSecretKey = await config.get("aws-upload-docs-secretkey"); - - const s3 = new AWS.S3({ - apiVersion: '2006-03-01', - accessKeyId: awsAccessId, - secretAccessKey: awsSecretKey - }); - - const added = [], removed = [], changed = [], upload = []; - - const basedir = path.resolve(__dirname, "../../docs"); - - const local = await getFiles(basedir); - const remote = await getKeys(s3); - - Object.keys(local).forEach((filename) => { - if (!remote[filename]) { - added.push(filename); - upload.push(filename); - } else if (remote[filename] != local[filename]) { - changed.push(filename); - upload.push(filename); - } - }); - - Object.keys(remote).forEach((filename) => { - if (!local[filename]) { - removed.push(filename); - } else if (!local[filename] && remote[filename] != local[filename]) { - changed.push(filename); - upload.push(filename); - } - }); - - console.log('Added: ', added.length); - console.log('Removed: ', removed.length); - console.log('Changed: ', changed.length); - - for (let i = 0; i < upload.length; i++) { - const filename = upload[i]; - const content = fs.readFileSync(path.resolve(basedir, filename)); - console.log(`Uploading: ${ filename } (${ content.length } bytes)`); - await putObject(s3, filename, content); - } -})(); diff --git a/admin/config.js b/admin/config.js deleted file mode 100644 index 9b1a92ff4..000000000 --- a/admin/config.js +++ /dev/null @@ -1,120 +0,0 @@ -"use strict"; - -const fs = require("fs"); -const os = require("os"); -const resolve = require("path").resolve; - -const AES = require("aes-js"); -const scrypt = require("scrypt-js"); - -const { prompt } = require("../packages/cli"); -const randomBytes = require("../packages/random").randomBytes; -const computeHmac = require("../packages/sha2").computeHmac; - -const colorify = require("./log").colorify; - -function getScrypt(message, password, salt) { - let progressBar = prompt.getProgressBar(message); - return scrypt.scrypt(Buffer.from(password), Buffer.from(salt), (1 << 17), 8, 1, 64, progressBar); -} - -function Config(filename) { - this.salt = null; - this.dkey = null; - this.values = { }; - this.canary = ""; - this.filename = filename; -} - -Config.prototype.load = async function() { - if (this.dkey) { return; } - - let data = null; - if (fs.existsSync(this.filename)) { - data = JSON.parse(fs.readFileSync(this.filename)); - } else { - data = { - salt: Buffer.from(randomBytes(32)).toString("hex") - }; - } - - this.canary = data.canary || ""; - - this.salt = data.salt; - - const password = await prompt.getPassword(colorify("Password (config-store): ", "bold")); - - this.dkey = await getScrypt(colorify("Unlocking config", "bold"), password, this.salt); - - if (data.ciphertext) { - const ciphertext = Buffer.from(data.ciphertext, "base64"); - const iv = Buffer.from(data.iv, "base64"); - const aes = new AES.ModeOfOperation.ctr(this.dkey.slice(0, 32), new AES.Counter(iv)); - const plaintext = aes.decrypt(ciphertext); - const hmac = computeHmac("sha512", this.dkey.slice(32, 64), plaintext); - if (hmac !== data.hmac) { - throw new Error("wrong password"); - } - - this.values = JSON.parse(Buffer.from(plaintext).toString()); - } -}; - -Config.prototype.keys = async function() { - await this.load(); - return Object.keys(this.values); -} - -Config.prototype.save = function() { - this.values._junk = Buffer.from(randomBytes(16 + parseInt(Math.random() * 48))).toString("base64") - - const plaintext = Buffer.from(JSON.stringify(this.values)); - - const iv = Buffer.from(randomBytes(16)); - const hmac = computeHmac("sha512", this.dkey.slice(32, 64), plaintext); - - const aes = new AES.ModeOfOperation.ctr(this.dkey.slice(0, 32), new AES.Counter(iv)); - const ciphertext = Buffer.from(aes.encrypt(plaintext)); - - const data = { - ciphertext: ciphertext.toString("base64"), - iv: iv.toString("base64"), - salt: this.salt, - hmac: hmac, - canary: this.canary - }; - - fs.writeFileSync(this.filename, JSON.stringify(data, null, 2)); -} - -Config.prototype.get = async function(key) { - await this.load(); - return this.values[key]; -}; - -Config.prototype.set = async function(key, value) { - await this.load(); - this.values[key] = value; - this.save(); -}; - -Config.prototype.lock = function() { - this.salt = this.dkey = null; -} - -const config = new Config(resolve(os.homedir(), ".ethers-dist")); - -module.exports = { - get: function(key) { - return config.get(key); - }, - set: function(key, value) { - config.set(key, value); - }, - keys: function() { - return config.keys(); - }, - lock: function() { - config.lock(); - } -} diff --git a/admin/depgraph.js b/admin/depgraph.js deleted file mode 100644 index 42b887f60..000000000 --- a/admin/depgraph.js +++ /dev/null @@ -1,94 +0,0 @@ -"use strict"; - -const fs = require("fs"); - -const { loadJson, resolve } = require("./utils"); - -const ROOT = resolve("packages"); - -const dirnames = fs.readdirSync(ROOT); - -function loadPackage(dirname) { - return loadJson(resolve("packages", dirname, "package.json")); -} - -function getOrdered(skipNobuild) { - let packages = { }; - let filenames = { }; - - let addDeps = (name, depends) => { - Object.keys(depends).forEach((dep) => { - // Not a package we manage - if (packages[dep] == null) { return; } - deps[name][dep] = true; - }); - } - - for (let i = 0; i < dirnames.length; i++) { - let dirname = dirnames[i]; - let info = loadPackage(dirname); - if (skipNobuild && info._ethers_nobuild) { continue; } - packages[info.name] = info; - filenames[info.name] = dirname; - } - - // Maps names to list of dependencies; { [ name:string]: Array } - let deps = { }; - let depGraph = { }; - - Object.keys(packages).forEach((name) => { - let info = packages[name]; - deps[info.name] = { }; - addDeps(info.name, info.dependencies || { }); - addDeps(info.name, info.devDependencies || { }); - deps[info.name] = Object.keys(deps[info.name]); - deps[info.name].sort(); - }); - - let ordered = [ ]; - let remaining = Object.keys(deps); - - let isSatisfied = (name) => { - for (let i = 0; i < deps[name].length; i++) { - if (ordered.indexOf(deps[name][i]) === -1) { return false; } - } - return true; - } - - while (remaining.length) { - let bail = true; - for (let i = 0; i < remaining.length; i++) { - if (!isSatisfied(remaining[i])) { continue; } - bail = false; - ordered.push(remaining[i]); - remaining.splice(i, 1); - break; - } - - if (bail) { - throw new Error("Nothing processed; circular dependencies..."); - } - } - - return ordered.map((name) => filenames[name]); -} - -function sort(dirnames) { - let ordered = getOrdered(); - dirnames.sort((a, b) => { - let ai = ordered.indexOf(local.loadPackage(a).name); - let bi = ordered.indexOf(local.loadPackage(b).name); - if (ai === -1 || bi === -1) { - throw new Error("unknown dirname - " + [a, b].join(", ")); - } - return ai - bi; - }); -} - -module.exports = { - dirnames: dirnames, - getOrdered: getOrdered, - loadPackage: loadPackage, - ROOT: ROOT, - sort: sort -} diff --git a/admin/git.js b/admin/git.js deleted file mode 100644 index 186431c64..000000000 --- a/admin/git.js +++ /dev/null @@ -1,186 +0,0 @@ -"use strict"; - -const resolve = require("path").resolve; -const spawn = require("child_process").spawn; - -const semver = require("semver"); - -const { run } = require("./build"); -const { loadPackage } = require("./local"); - -function git(args) { - return run("git", args); -} - -function getStatus(filename) { - return git([ "status", "-s", resolve(__dirname, "..", filename) ]).then((result) => { - result = result.trim(); - if (result === "") { return "unmodified"; } - switch (result.substring(0, 2)) { - case 'M ': return "modified"; - case 'A ': return "added"; - case 'D ': return "deleted"; - case 'R ': return "renamed"; - case 'C ': return "copied"; - case 'U ': return "updated"; - case '??': return "untracked"; - } - console.log(result); - return "unknown"; - }); -} - -async function getChanges(latest) { - let diff = await git(["diff", "--name-only", latest ]); - - // Map dirname => { dist: [ ], src: [ ] } - let changes = { "_": { filename: "_", dist: [], src: [] } }; - - diff.split("\n").forEach((line) => { - // e.g. packages/constants/index.d.ts - let comps = line.trim().split("/"); - - // Track non-packages as dist - if (comps.length < 2 || comps[0] !== "packages") { - let filename = comps.join("/").trim(); - if (filename === "") { return; } - changes._.dist.push(filename); - return; - } - - let name = loadPackage(comps[1]).name; - - let change = changes[name]; - if (!change) { - change = { filename: comps[1], dist: [ ], src: [ ] } - changes[name] = change; - } - - // Split changes into source changes (src.ts/) or dist changes (output of TypeScript) - if (comps[2] === "src.ts") { - change.src.push(comps.join("/")); - } else { - change.dist.push(comps.join("/")); - } - }); - - return changes; -} - -function getLatestTag() { - let seq = Promise.resolve(); - - // @TODO: Pull - if (false) { - seq = seq.then(() => { - console.log("Pulling remote changes..."); - return git([ "pull" ]); - }); - } - - seq = seq.then(() => { - return git([ "tag" ]).then((tags) => { - tags = tags.split("\n").filter(tag => (tag.match(/^v[0-9]+\.[0-9]+\.[0-9]+\-/))); - tags.sort(semver.compare) - return tags.pop(); - }); - }); - - return seq; -} - -function findChanges(latest) { - let seq = Promise.resolve(); - - seq = seq.then(() => { - return git(["diff", "--name-only", latest, "HEAD" ]).then((result) => { - let filenames = { }; - result.split("\n").forEach((line) => { - // e.g. packages/constants/index.d.ts - let comps = line.trim().split("/"); - if (comps.length < 2) { return; } - filenames[comps[1]] = true; - }); - return Object.keys(filenames); - }); - }); - - seq = seq.then((filenames) => { - return filenames.map((filename) => { - let name = packages[filename].name; - return { - filename: filename, - name: name, - localVersion: getLocalVersion(name), - } - }); - }); - - seq = seq.then((packages) => { - let seq = Promise.resolve(); - packages.forEach((p) => { - seq = seq.then(() => { - return getNpmVersion(p.name).then((version) => { - p.npmVersion = version; - }); - }); - }); - return seq.then(() => packages); - }); - return seq; -} - -async function getGitTag(filename) { - let result = await git([ "log", "-n", "1", "--", filename ]); - result = result.trim(); - if (!result) { return null; } - result = result.match(/^commit\s+([0-9a-f]{40})\n/i); - if (!result) { return null; } - return result[1]; -} - -async function getDiff(filename, tag, nameOnly) { - if (tag == null) { tag = "HEAD"; } - let cmd = [ "diff", "--name-only", tag, "--", filename ] - if (!nameOnly) { cmd.splice(1, 1); } - try { - let result = await git(cmd); - result = result.trim(); - if (result === "") { return [ ]; } - return result.split("\n"); - } catch (error) { - // This tag does not exist, so compare against beginning of time - // This happens when there is a new history (like an orphan branch) - if (error.stderr.trim().match(/^fatal: bad object/)) { - console.log("Could not find history; showing all"); - let cmd = [ "rev-list", "--max-parents=0", "HEAD" ]; - let tag = await git(cmd); - return getDiff(filename, tag.trim(), nameOnly); - } - - throw error; - } -} - -async function getUntracked(filename) { - let cmd = [ "ls-files", "-o", "--exclude-standard"]; - if (filename) { - cmd.push("--"); - cmd.push(filename); - } - let result = await git(cmd); - result = result.trim(); - if (result === "") { return [ ]; } - return result.split("\n"); -} - -module.exports = { - findChanges: findChanges, - getChanges: getChanges, - getDiff: getDiff, - getGitTag: getGitTag, - getLatestTag: getLatestTag, - getStatus: getStatus, - getUntracked: getUntracked, - run: git, -} diff --git a/admin/github.js b/admin/github.js deleted file mode 100644 index b1a559bae..000000000 --- a/admin/github.js +++ /dev/null @@ -1,162 +0,0 @@ -"use strict"; - -const fs = require("fs"); -const { resolve } = require("path"); -const zlib = require("zlib"); - -const { id } = require("../packages/hash"); -const { fetchJson } = require("../packages/web"); - -const CacheDir = resolve(__dirname, "../github-cache/"); - -function addResponse(result, response) { - return { result, response }; -} - -function loadFile(filename) { - return JSON.parse(zlib.gunzipSync(fs.readFileSync(filename)).toString()); - //return JSON.parse(fs.readFileSync(filename).toString()); -} - -// @TODO: atomic -function saveFile(filename, content) { - fs.writeFileSync(filename, zlib.gzipSync(JSON.stringify(content))); - //fs.writeFileSync(filename, JSON.stringify(content)); -} - -function mockFetchJson(url, body, headers) { - return { - result: null, - response: { - statusCode: 304 - } - } -} - -async function _fetchGitHub(user, password, fetchJson, url) { - const result = [ ]; - while (true) { - - const filename = resolve(CacheDir, id(url).substring(2, 14)); - - const headers = { - "User-Agent": "ethers-io", - }; - - let items = null; - let link = null; - try { - const data = loadFile(filename); - headers["if-none-match"] = data.etag; - items = data.items; - link = data.link; - } catch (error) { - if (error.code !== "ENOENT") { throw error; } - } - - const fetch = await fetchJson({ - url: url, - user: user, - password: password, - headers: headers - }, null, addResponse); - - // Cached response is good; use it! - if (fetch.response.statusCode !== 304) { - items = fetch.result; - if (fetch.response.headers) { - link = (fetch.response.headers.link || null); - } - if (fetch.response.headers.etag){ - saveFile(filename, { - timestamp: (new Date()).getTime(), - url: url, - link: link, - etag: fetch.response.headers.etag, - items: items, - version: 1 - }); - } - } - - items.forEach((item) => { result.push(item)}); - - url = null; - (link || "").split(",").forEach((item) => { - if (item.indexOf('rel="next"') >= 0) { - const match = item.match(/<([^>]*)>/); - if (match) { url = match[1]; } - } - }); - - if (!url) { break; } - } - return result; -} - -async function fetchGitHub(user, password, url, cacheOnly) { - if (cacheOnly) { - return await _fetchGitHub("none", "none", mockFetchJson, url); - } - - const results = await _fetchGitHub(user, password, fetchJson, url); - return results; -} - - -async function _getIssues(user, password) { - const cacheOnly = (user == null); - - let issues = await fetchGitHub(user, password, "https:/\/api.github.com/repos/ethers-io/ethers.js/issues?state=all&per_page=100", cacheOnly) - if (!cacheOnly) { console.log(`Found ${ issues.length } issues`); } - const result = [ ]; - for (let i = 0; i < issues.length; i++) { - const issue = issues[i]; - let comments = await fetchGitHub(user, password, issue.comments_url, cacheOnly); - result.push({ issue, comments}); - if (!cacheOnly) { console.log(` Issue ${ issue.number }: ${ comments.length } comments`); } - } - result.sort((a, b) => (a.issue.number - b.issue.number)); - return result; -} - -function getIssues() { - return _getIssues(); -} - -function syncIssues(user, password) { - return _getIssues(user, password); -} - -async function createRelease(user, password, tagName, title, body, prerelease, commit) { - const payload = { - tag_name: tagName, - target_commitish: (commit || "master"), - name: title, - body: body, - //draft: true, - draft: false, - prerelease: !!prerelease - }; - - const headers = { - "User-Agent": "ethers-io", - }; - - const result = await fetchJson({ - url: "https://api.github.com/repos/ethers-io/ethers.js/releases", - user: user, - password: password, - headers: headers - }, JSON.stringify(payload)); - - - return result.html_url; -} - -module.exports = { - getIssues, - syncIssues, - createRelease, -} - diff --git a/admin/index.js b/admin/index.js deleted file mode 100644 index 51dff4312..000000000 --- a/admin/index.js +++ /dev/null @@ -1,401 +0,0 @@ -"use strict"; - -const fs = require("fs"); -const resolve = require("path").resolve; - -const diff = require("diff"); -const semver = require("semver"); - -const { prompt } = require("../packages/cli"); - -const build = require("./build"); -const changelog = require("./changelog"); -const depgraph = require("./depgraph"); -const { colorify, colorifyStatus, log } = require("./log"); -const config = require("./config") -const git = require("./git"); -const local = require("./local"); -const npm = require("./npm"); -const utils = require("./utils"); - -/* -async function runChanged(dirnames, callback) { - try { - await callback(dirname, info, npmInfo); - } catch (error) { - console.log(error); - console.log(colorify("Aborting! " + error.message)); - return; - } - } - } -} -*/ -/* - if (diff) { - } else { -*/ - -async function runDiff(dirnames) { - // Default to all packages - if (dirnames == null || dirnames.length === 0) { dirnames = local.dirnames; } - - for (let i = 0; i < dirnames.length; i++) { - let dirname = dirnames[i]; - - // Get local (update the tarballHash) and remote package.json - let info = await local.loadPackage(dirname); - let npmInfo = await npm.getPackageVersion(info.name); - if (!npmInfo) { npmInfo = { gitHead: "HEAD", version: "NEW" }; } - - let delta = await git.getDiff(resolve(__dirname, "../packages", dirname), npmInfo.gitHead); - - if (delta.length === 0) { continue; } - - // Bump the version if necessary - if (info.version === npmInfo.version) { - info.version = semver.inc(info.version, "patch"); - } - - console.log(colorify(": ") + info.name); - console.log(colorify(" (run update to bump version)")); - console.log(" " + npmInfo.gitHead) - console.log(" " + npmInfo.version + colorify(" => ", "bold") + info.version) - - console.log(colorify(" Diff", "bold")); - delta.forEach((line) => { - let color = "blue"; - switch (line.substring(0, 1)) { - case '+': - color = "green"; - break; - case '-': - color = "red"; - break; - case ' ': - color = "normal"; - break; - } - console.log(" " + colorify(line, color)); - }); - - console.log(""); - } - - console.log(""); -} - -async function updateChangelog() { - let filename = resolve(local.ROOT, "../CHANGELOG.md"); - - let lastVersion = await git.getLatestTag(); - let newVersion = "v" + local.getVersion("ethers"); - - let current = fs.readFileSync(filename).toString(); - let log = await changelog.generate(); - if (log === current) { return; } - - let changes = diff.createTwoFilesPatch("CHANGELOG-old.md", "CHANGELOG.md", current, log, lastVersion, newVersion); - console.log(changes); - - try { - let response = await prompt.getChoice(colorify("Accept changes?", "bold"), "yn", "n"); - if (response === "n") { throw new Error("Not changing."); } - } catch (error) { - console.log("Abort: " + error.message); - return; - } - - fs.writeFileSync(filename, log); -} - -// Updates the dependency-graph (tsconfig.project.json) so the build order is correct -async function runUpdateDepgraph() { - log(``); - let ordered = depgraph.getOrdered(); - - let path = resolve(local.ROOT, "../tsconfig.project.json") - - let projectConfig = local.loadJson(path); - projectConfig.references = ordered.map((name) => ({ path: ("./packages/" + name) })); - local.saveJson(path, projectConfig); -} - -async function runUpdate(dirnames) { - - // Check for untracked files... - let untracked = [ ]; - if (dirnames == null || dirnames.length === 0) { - dirnames = local.dirnames; - let filenames = await git.getUntracked(resolve(__dirname, "..")); - for (let i = 0; i < filenames.length; i++) { - untracked.push(filenames[i]); - } - } else { - for (let i = 0; i < dirnames.length; i++) { - let filenames = await git.getUntracked(resolve(local.ROOT, dirnames[i])); - for (let j = 0; j < filenames.length; j++) { - untracked.push(filenames[j]); - } - } - } - - // Untracked files! Abort. - if (untracked.length) { - log(""); - untracked.forEach((filename) => { - console.log(" " + filename); - }); - log(""); - return; - } - - log(``); - await build.runBuild() - - log(""); - - // @TODO: Root - - // Update all the package.json and _version.ts - let progress = prompt.getProgressBar(colorify("Updating versions", "bold")); - for (let i = 0; i < dirnames.length; i++) { - progress(i / dirnames.length); - - let dirname = dirnames[i]; - let path = resolve(__dirname, "../packages/", dirname); - - // Get local package.json (update the tarballHash) - let info = await local.updatePackage(dirname); - - // Get the remote package.json (or sub in a placeholder for new pacakges) - let npmInfo = await npm.getPackageVersion(info.name); - if (!npmInfo) { npmInfo = { version: "NEW" }; } - - if (info.tarballHash === npmInfo.tarballHash) { continue; } - - // Bump the version if necessary - if (info.version === npmInfo.version) { - let newVersion = semver.inc(info.version, "patch"); - - // Write out the _version.ts - if (!info._ethers_skipPrepare) { - let code = "export const version = " + JSON.stringify(newVersion) + ";\n"; - fs.writeFileSync(resolve(path, "src.ts/_version.ts"), code); - } - - // Update the package.json (we do this after _version, so if we fail, - // this remains old; which is what triggers the version bump) - info = await local.updatePackage(dirname, { version: newVersion }); - } - } - progress(1); - - // Build the TypeScript sources - log(""); - try { - await build.runTsc(); - } catch (error) { - console.log(error); - log(""); - return; - } - - // Run the dist - // @TODO: - - // Update the tarball hash now that _version and package.json may have changed. - progress = prompt.getProgressBar(colorify("Updating tarballHash", "bold")); - for (let i = 0; i < dirnames.length; i++) { - progress(i / dirnames.length); - await local.updatePackage(dirnames[i]); - } - progress(1); - - // Show the changed files (compared to npm) - for (let i = 0; i < dirnames.length; i++) { - let dirname = dirnames[i]; - - // Get local package.json - let info = await local.loadPackage(dirname); - let path = resolve(__dirname, "../packages/", dirname); - - // Get the remote package.json (or sub in a placeholder for new pacakges) - let npmInfo = await npm.getPackageVersion(info.name); - if (!npmInfo) { npmInfo = { version: "NEW" }; } - - // No change - if (info.tarballHash === npmInfo.tarballHash) { continue; } - - let gitHead = await git.getGitTag(path); - - log(`: ${info.name}`); - log(` (bumping version)`); - log(` ${npmInfo.version} => ${info.version}`) - log(` `); - let filenames = await git.getDiff(resolve(__dirname, "../packages", dirname), npmInfo.gitHead, true); - filenames.forEach((filename) => { - let short = filename.split("/").slice(1).join("/"); - if (short.indexOf("/src.ts/") >= 0) { - log(` `); - } else { - log(` ${short}`); - } - }); - log(""); - } - - // @TODO: Changelog - await updateChangelog(); -} - -async function runAdd(type, names) { - let latest = await git.getLatestTag(); - console.log(""); - console.log(colorify(": ") + latest); - console.log(""); - - let changes = await git.getChanges("HEAD"); - - if (!names || names.length === 0) { - names = Object.keys(changes); - } - - let filenames = [ ]; - for (let i = 0; i < names.length; i++) { - let name = names[i]; - let change = changes[name] || changes[(packages[name] || {}).name]; - if (!change) { return; } - change[type].forEach((filename) => { - filenames.push(filename); - }); - } - - if (filenames.length === 0) { - console.log(colorify("")); - console.log(""); - return; - } - - for (let i = 0; i < filenames.length; i++) { - let filename = filenames[i]; - let status = await git.getStatus(filename); - console.log(" " + colorifyStatus(status) + ": " + utils.repeat(" ", 10 - status.length) + filename); - } - - console.log(""); - - try { - let response = await prompt.getChoice(colorify("Add these files?", "bold"), "yn", "n"); - if (response === "n") { throw new Error("Not adding."); } - } catch (error) { - console.log("Abort: " + error.message); - return; - } - - let params = filenames.map((f) => f); //resolve(ROOT, f)); - params.unshift("--"); - params.unshift("add"); - - console.log("git " + params.join(" ")); - - try { - await git.run(params); - } catch (error) { - console.log("Error: (status: " + error.code + ")"); - console.log(" " + error.stderr); - return; - } - - console.log("Added."); -} - -function runDist() { - // Run npm dist - // Generate changelog - // run status to update all the package - // add dist files? -} - -async function runPublish(dirnames) { - - // @TODO: Make sure there are no staged files - - // @TODO: Make sure the repo has been pushed - - // @TODO: Run the publish in the correct order - - // Get the authentication token from our encrypted store - let token = await config.get("token"); - token = token.trim().split("="); - - let options = { - npmVersion: "ethers-dist@0.0.0", - tag: "next" - }; - - // Set the authentication token - options[token[0]] = token[1]; - - if (dirnames == null || dirnames.length === 0) { dirnames = local.dirnames; } - depgraph.sort(dirnames); - - await runChanged(dirnames, async (dirname, info, npmInfo) => { - console.log(colorify(" ") + info.name + "...") - console.log(colorify(" Version: ", "blue") + npmInfo.version + colorify(" => ", "bold") + info.version); - - let success = await npm.publish(dirname, options); - if (!success) { - console.log(colorify(" ")); - throw new Error(""); - } - console.log(colorify(" ")); - }); -} - -async function runTest() { - let r = await git([ "tag", "--porcelain", "-a", "-m", "Title of Release\n\nHello\n-----\n\nTesting 4 **bold** #1\nHello World", "test6", "HEAD" ]); - console.log(r); - try { - r = await git([ "push", "--tags" ]) - } catch(e) { console.log(e); } - console.log(r); -} - -(function() { - let args = process.argv.slice(2); - switch (args[0]) { - - // Compare published to current stage - case "diff": - return runDiff(args.slice(1)); - - // Add unchecked-in source files - case "add-source": - return runAdd("src", args.slice(1)); - - // Update all package.json. the changelog and dist files - case "update": - return runUpdate(args.slice(1)); - - // Update dependency graph (./tsconfig-project.json) - case "update-depgraph": - return runUpdateDepgraph(); - - // Add unchecked-in dist files - case "add-dist": - return runAdd("dist", args.slice(1)); - - - // Add unchecked-in source files - case "changelog": - return updateChangelog(); - - // Add unchecked-in source files - case "publish": - return runPublish(args.slice(1)); - - case "test": - return runTest(); - } -})(); diff --git a/admin/local.js b/admin/local.js deleted file mode 100644 index 8fed2f596..000000000 --- a/admin/local.js +++ /dev/null @@ -1,101 +0,0 @@ -"use strict"; - -const packlist = require("npm-packlist"); -const tar = require("tar"); - -const keccak256 = (function() { - try { - return require("../packages/keccak256").keccak256; - } catch (error) { - console.log("Cannot load Keccak256 (maybe not built yet? Not really a problem for most things)"); - return null; - } -})(); - -const { dirnames, loadPackage, ROOT } = require("./depgraph"); -const { resolve, saveJson } = require("./utils"); - -function sorted(obj) { - if (Array.isArray(obj)) { return obj.map(sorted); } - if (obj == null || typeof(obj) !== "object") { return obj; } - - const keys = Object.keys(obj); - keys.sort(); - - const result = { }; - keys.forEach((key) => { result[key] = sorted(obj[key]); }); - return result; -} - -function savePackage(dirname, info) { - return saveJson(resolve(ROOT, dirname, "package.json"), sorted(info)); -} - -async function createTarball(dirname) { - let base = resolve(ROOT, dirname); - - // From NPM publish, create the packed version - let files = await packlist({ path: base }); - files = files.map((f) => ("./" + f)); - - let options = { - cwd: base, - prefix: 'package/', - portable: true, - sync: true, - // Provide a specific date in the 1980s for the benefit of zip, - // which is confounded by files dated at the Unix epoch 0. - mtime: new Date('1985-10-26T08:15:00.000Z'), - gzip: true - }; - - // Take the hash of the package sans - return tar.create(options, files).read(); -} - -async function updatePackage(dirname, values) { - let info = loadPackage(dirname); - - if (values) { - for (let key in values) { - info[key] = values[key]; - } - } - /* - ["dependencies", "devDependencies"].forEach((key) => { - let deps = info[key] || []; - for (let name in deps) { - if (name.substring(0, "@ethersproject".length) === "@ethersproject" || name === "ethers") { - deps[name] = ">5.0.0-beta.0"; - } - } - }); - */ - - //if (dirname !== "ethers") { - // delete info.publishConfig.tag; - //} - - // Create a normalized version sans tarballHash to compute the tarballHash - delete info.tarballHash; - savePackage(dirname, info); - - // Compute the tarballHash - let tarball = await createTarball(dirname); - info.tarballHash = keccak256(tarball); - - // Save the updated package.json to disk - savePackage(dirname, info); - - return info; -} - -module.exports = { - ROOT: ROOT, - createTarball: createTarball, - dirnames: dirnames, - getVersion: function(dirname) { return ((loadPackage(dirname) || {}).version || null); }, - loadPackage: loadPackage, - savePackage: savePackage, - updatePackage: updatePackage, -} diff --git a/admin/log.js b/admin/log.js deleted file mode 100644 index c740f26ff..000000000 --- a/admin/log.js +++ /dev/null @@ -1,53 +0,0 @@ -"use strict"; - -function getColor(color) { - if (!color || color === "normal") { return "\x1b[0m"; } - return "\x1b[1m" + ({ - blue: "\x1b[34m", - cyan: "\x1b[36m", - green: "\x1b[32m", - magenta: "\x1b[35m", - red: "\x1b[31m", - yellow: "\x1b[33m", - bold: "" - })[color]; -} - -// See: https://stackoverflow.com/questions/9781218/how-to-change-node-jss-console-font-color -let disableColor = !(process.stdout.isTTY); -function colorify(message, color) { - if (color) { - if (disableColor) { return message; } - return getColor(color) + message + getColor(); - } - - return message.replace(/<([^:]*):((?:[^<>\\]|\\.)*)>/g, (all, color, message) => { - message = message.replace("\\>", ">"); - if (disableColor) { return message; } - return getColor(color) + message + getColor(); - }); -} - -function colorifyStatus(status) { - switch (status) { - case "modified": return colorify(""); - case "added": return colorify(""); - case "deleted": return colorify(""); - case "unmodified": return colorify(""); - } - return status; -} - -function log(message, color) { - if (color) { - console.log(colorify(message, color)); - } else { - console.log(colorify(message)); - } -} - -module.exports = { - colorify: colorify, - colorifyStatus: colorifyStatus, - log: log -} diff --git a/admin/npm.js b/admin/npm.js deleted file mode 100644 index e785c3b1a..000000000 --- a/admin/npm.js +++ /dev/null @@ -1,104 +0,0 @@ -"use strict"; - -const resolve = require("path").resolve; - -const npmpub = require("libnpmpublish"); -const semver = require("semver"); - -const local = require("./local"); - -const keccak256 = require("../packages/keccak256").keccak256; -const fetchJson = require("../packages/web").fetchJson; -const { prompt } = require("../packages/cli"); - -const colorify = require("./log").colorify; -const git = require("./git"); - - -let cache = { }; - -async function getPackage(name) { - if (cache[name]) { return cache[name]; } - - return fetchJson("http:/" + "/registry.npmjs.org/" + name).then((result) => { - cache[name] = result; - return result; - }, (error) => { - if (error.status === 404) { - return null; - } - throw error; - }); -} - -async function getVersion(name) { - return getPackage(name).then((result) => { - if (!result) { return null; } - let versions = Object.keys(result.versions); - versions.sort(semver.compare) - return versions.pop(); - }); -} - -async function getPackageVersion(name, version) { - let info = await getPackage(name) - if (!info) { return null; } - - if (version == null) { - let versions = Object.keys(info.versions); - versions.sort(semver.compare); - version = versions.pop(); - } - - return info.versions[version] || null; -} - -async function getTarballHash(name, version) { - let info = await getPackageVersion(name, version); - return (info || {}).tarballHash; -} - -async function _publish(info, tarball, options) { - try { - let result = await npmpub.publish(info, tarball, options); - return result; - } catch (error) { - - // We need an OTP - if (error.code === "EOTP") { - try { - let otp = await prompt.getMessage(colorify("Enter OTP: ", "bold")); - options.otp = otp.replace(" ", ""); - } catch (error) { - - // CTRL-C - if (error.message === "cancelled") { - return false; - } - - // Something unexpected... - throw error; - } - - // Retry with the new OTP - return _publish(info, tarball, options); - } - throw error; - } -} - -async function publish(dirname, options) { - let info = local.loadPackage(dirname); - info.gitHead = await git.getGitTag(resolve(__dirname, "../packages/", dirname)); - if (info.gitHead == null) { throw new Error("no git tag found - " + dirname); } - let tarball = await local.createTarball(dirname); - return _publish(info, tarball, options); -} - -module.exports = { - getPackage: getPackage, - getPackageVersion: getPackageVersion, - getTarballHash: getTarballHash, - getVersion: getVersion, - publish: publish, -}; diff --git a/admin/test-parity/parity-dev.json b/admin/test-parity/parity-dev.json deleted file mode 100644 index 56a00bf54..000000000 --- a/admin/test-parity/parity-dev.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "name": "DevelopmentChain", - "engine": { - "instantSeal": null - }, - "params": { - "gasLimitBoundDivisor": "0x0400", - "accountStartNonce": "0x0", - "maximumExtraDataSize": "0x20", - "minGasLimit": "0x1388", - "networkID" : "0x11", - "registrar" : "0x0000000000000000000000000000000000001337", - "maxCodeSize": 24576, - "maxCodeSizeTransition": "0x0", - "eip98Transition": "0x7fffffffffffff", - "eip140Transition": "0x0", - "eip145Transition": "0x0", - "eip150Transition": "0x0", - "eip155Transition": "0x0", - "eip160Transition": "0x0", - "eip161abcTransition": "0x0", - "eip161dTransition": "0x0", - "eip211Transition": "0x0", - "eip214Transition": "0x0", - "eip658Transition": "0x0", - "wasmActivationTransition": "0x0" - }, - "genesis": { - "seal": { - "generic": "0x0" - }, - "difficulty": "0x20000", - "author": "0x0000000000000000000000000000000000000000", - "timestamp": "0x00", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "extraData": "0x", - "gasLimit": "0x7A1200" - }, - "accounts": { - "0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, - "0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, - "0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, - "0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, - "0000000000000000000000000000000000000005": { "balance": "1", "builtin": { "name": "modexp", "activate_at": 0, "pricing": { "modexp": { "divisor": 20 } } } }, - "0000000000000000000000000000000000000006": { "balance": "1", "builtin": { "name": "alt_bn128_add", "activate_at": 0, "pricing": { "linear": { "base": 500, "word": 0 } } } }, - "0000000000000000000000000000000000000007": { "balance": "1", "builtin": { "name": "alt_bn128_mul", "activate_at": 0, "pricing": { "linear": { "base": 40000, "word": 0 } } } }, - "0000000000000000000000000000000000000008": { "balance": "1", "builtin": { "name": "alt_bn128_pairing", "activate_at": 0, "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } }, - "0x7454a8f5a7c7555d79b172c89d20e1f4e4cc226c": { "balance": "1606938044258990275541962092341162602522202993782792835301376" } - } -} diff --git a/admin/test-parity/parity-dev.pwds b/admin/test-parity/parity-dev.pwds deleted file mode 100644 index 8b1378917..000000000 --- a/admin/test-parity/parity-dev.pwds +++ /dev/null @@ -1 +0,0 @@ - diff --git a/admin/test-parity/parity-keys/UTC--2019-06-25T00-14-25Z--24d70b97-fff9-d322-e760-4b8cc2e21751 b/admin/test-parity/parity-keys/UTC--2019-06-25T00-14-25Z--24d70b97-fff9-d322-e760-4b8cc2e21751 deleted file mode 100644 index 2871539ea..000000000 --- a/admin/test-parity/parity-keys/UTC--2019-06-25T00-14-25Z--24d70b97-fff9-d322-e760-4b8cc2e21751 +++ /dev/null @@ -1 +0,0 @@ -{"id":"24d70b97-fff9-d322-e760-4b8cc2e21751","version":3,"crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"45d392cd16dbbd5c0f5b2d145c112da9"},"ciphertext":"b001ccd09fc5431dc055975b58ee61f86e85529245506c04182c902716e750e5","kdf":"pbkdf2","kdfparams":{"c":10240,"dklen":32,"prf":"hmac-sha256","salt":"028594da27a0e864105f33b912e5dc6ce7c75ecd13c81bfc158fe963d30c93bb"},"mac":"374bf2e9144b74b889708abc19e9ebc164f90bc27e83fd9f01da4571a9f81a70"},"address":"7454a8f5a7c7555d79b172c89d20e1f4e4cc226c","name":"","meta":"{}"} \ No newline at end of file diff --git a/admin/utils.js b/admin/utils.js deleted file mode 100644 index b18ddc5a2..000000000 --- a/admin/utils.js +++ /dev/null @@ -1,64 +0,0 @@ -"use strict"; - -const fs = require("fs"); -const _resolve = require("path").resolve; - -function repeat(chr, length) { - let result = chr; - while (result.length < length) { result += chr; } - return result; -} - -function zpad(value) { - value = String(value); - while (value.length < 2) { value = "0" + value; } - return value; -} - -function getDate(date) { - return [ - date.getFullYear(), - zpad(date.getMonth() + 1), - zpad(date.getDate()) - ].join("-"); -} - -function getDateTime(date) { - return getDate(date) + " " + [ - zpad(date.getHours()) , - zpad(date.getMinutes() + 1) - ].join(":"); -} - -function today() { - return getDate(new Date()); -} - -function loadJson(filename) { - return JSON.parse(fs.readFileSync(filename).toString()); -} - -// @TODO: atomic write -function saveJson(filename, json) { - fs.writeFileSync(filename, JSON.stringify(json, null, 2) + "\n"); -} - -function resolve(...args) { - args = args.slice(); - args.unshift(".."); - args.unshift(__dirname); - return _resolve.apply(null, args); -} - -module.exports = { - resolve: resolve, - - loadJson: loadJson, - saveJson: saveJson, - - repeat: repeat, - - today: today, - getDate: getDate, - getDateTime: getDateTime -} diff --git a/lerna.json b/lerna.json deleted file mode 100644 index a2bb50ba7..000000000 --- a/lerna.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "packages": [ - "packages/*" - ], - "version": "independent" -}