Skip to content

Commit

Permalink
feat: dev mkcert downloader
Browse files Browse the repository at this point in the history
  • Loading branch information
liuweiGL committed Mar 30, 2021
1 parent 3105c9e commit ff9b411
Show file tree
Hide file tree
Showing 9 changed files with 3,562 additions and 591 deletions.
7 changes: 7 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ module.exports = {
{
allowSingleExtends: true
}
],
'no-empty-function': 'off',
'@typescript-eslint/no-empty-function': [
'error',
{
allow: ['constructors']
}
]
}
}
3,874 changes: 3,317 additions & 557 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"prettier": "^2.2.1",
"rollup": "^2.44.0",
"ts-node": "^9.1.1",
"typescript": "^4.2.3"
"typescript": "^4.2.3",
"vite": "^2.1.4"
}
}
5 changes: 5 additions & 0 deletions src/lib/constant.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
import os from 'os'
import path from 'path'

import pkg from '../../package.json'

export const PLUGIN_NAME = pkg.name

export const PLUGIN_DATA_DIR = path.join(os.homedir(), `.${PLUGIN_NAME}`)
32 changes: 32 additions & 0 deletions src/lib/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import fs from 'fs'
import path from 'path'

import { PLUGIN_DATA_DIR } from './constant'

export const resolvePath = (fileName: string) => {
return path.resolve(PLUGIN_DATA_DIR, fileName)
}

export const ensureDataDir = async () => {
try {
await fs.promises.access(PLUGIN_DATA_DIR, fs.constants.F_OK)
} catch {
await fs.promises.mkdir(PLUGIN_DATA_DIR, { recursive: true })
}
}

export const writeFile = async (
fileName: string,
data: string | Uint8Array
) => {
const filePath = resolvePath(fileName)
await ensureDataDir()
await fs.promises.writeFile(filePath, data)
return filePath
}

export const readFile = async (fileName: string) => {
const filePath = resolvePath(fileName)
await ensureDataDir()
return await fs.promises.readFile(filePath)
}
153 changes: 133 additions & 20 deletions src/mkcert/downloader.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,157 @@
import fs from 'fs'
import os from 'os'
import path from 'path'

import { Octokit } from '@octokit/rest'

import { PLUGIN_NAME } from '../lib/constant'
import log from '../lib/log'
import request from '../lib/request'
import { resolvePath, writeFile } from '../lib/util'

import VersionManger from './versionManger'

export type AssetInfo = {
version: string
downloadUrl: string
}

abstract class Downloader {
abstract getDownloadUrl(): Promise<string>
public assetInfo?: AssetInfo
private versionManger: VersionManger

constructor() {
this.versionManger = VersionManger.create()
}

abstract getAssetInfo(): Promise<AssetInfo>

private getSavedFileName() {
const fileName = 'mkcert'

return process.platform === 'win32' ? `${fileName}.ext` : fileName
}

private getSavedPath() {
return path.join(os.homedir(), PLUGIN_NAME, this.getSavedFileName())
protected getPlatformIdentifier() {
switch (process.platform) {
case 'win32':
return 'windows-amd64.exe'
case 'linux':
return process.arch === 'arm64'
? 'linux-arm64'
: process.arch === 'arm'
? 'linux-arm'
: 'linux-amd64'
case 'darwin':
return 'darwin-amd64'
default:
throw new Error('Unsupported platform')
}
}

private async download() {
const savedPath = this.getSavedPath()
const downloadUrl = await this.getDownloadUrl()
public async init() {
this.assetInfo = await this.getAssetInfo()
}

public async download() {
const fileName = this.getSavedFileName()

if (this.assetInfo === undefined) {
console.warn('Did you forget to call the [init] method to initialize')
log(
'The attachment information of mkcert has not been obtained, and the download has been skipped'
)
return resolvePath(fileName)
}

const { downloadUrl, version } = this.assetInfo
const shouldUpdate = await this.versionManger.shouldUpdate(version)

if (!shouldUpdate) {
log('Mkcert is already up to date, skip downloading')
return
}

log('Downloading the mkcert executable from %s', downloadUrl)

const { data } = await request.get(downloadUrl)
fs.mkdirSync(savedPath, { recursive: true })
fs.writeFileSync(savedPath, data)
const savedPath = await writeFile(fileName, data)

log('The mkcert has been saved to %s', savedPath)
return savedPath
}
}

class OfficialDownloader extends Downloader {
async getDownloadUrl() {
const octokit = new Octokit()
/**
* Download mkcert from github repo
*/
export class GithubDownloader extends Downloader {
public static create() {
return new GithubDownloader()
}

const res = await octokit.repos.getLatestRelease({
owner: 'FiloSottile',
repo: 'mkcert'
private constructor() {
super()
}

async getAssetInfo(): Promise<AssetInfo> {
let version: string | undefined
let downloadUrl: string | undefined

try {
const octokit = new Octokit()
const { data } = await octokit.repos.getLatestRelease({
owner: 'FiloSottile',
repo: 'mkcert'
})
const platformIdentifier = this.getPlatformIdentifier()

version = data.tag_name
downloadUrl = data.assets.find(item =>
item.name.includes(platformIdentifier)
)?.browser_download_url
} catch (e) {}

if (!(version && downloadUrl)) {
log('Github assets do not match, use coding.net mirror')
return CodingDownloader.create().getAssetInfo()
}

return {
downloadUrl,
version
}
}
}

/**
* Download mkcert from coding repo
*
* @see {https://help.coding.net/openapi}
*/
export class CodingDownloader extends Downloader {
private static CODING_OPEN_API = 'https://liuweigl.coding.net/open-api'

public static create() {
return new CodingDownloader()
}

private constructor() {
super()
}

async getAssetInfo(): Promise<AssetInfo> {
const { data } = await request({
method: 'POST',
url: CodingDownloader.CODING_OPEN_API,
params: {
Action: 'DescribeArtifactRepositoryFileList'
},
data: {
Action: 'DescribeArtifactRepositoryFileList',
Repository: 'mkcert',
Project: 'github',
PageSize: 10
}
})
console.log(res.data.assets)

console.log(data)

return data
}
}
47 changes: 47 additions & 0 deletions src/mkcert/versionManger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import log from '../lib/log'
import { readFile, writeFile } from '../lib/util'

const VERSION_FILE_NAME = 'version.txt'

const parseVersion = (version: string) => {
const str = version.trim().replace(/v|\./g, '')

return Number.parseInt(str)
}

class VersionManger {
public static create() {
return new VersionManger()
}

private constructor() {}

private async getCurrentVersion() {
try {
const version = await readFile(VERSION_FILE_NAME).toString()
return parseVersion(version)
} catch (e) {
return 0
}
}

public async updateCurrentVersion(version: string) {
try {
await writeFile(VERSION_FILE_NAME, version)
} catch (err) {
log('Failed to record mkcert version number: %s', err)
}
}

public async shouldUpdate(version: string) {
try {
const currentVersion = await this.getCurrentVersion()
const newVersion = parseVersion(version)
return currentVersion < newVersion
} catch (e) {
return true
}
}
}

export default VersionManger
19 changes: 19 additions & 0 deletions src/test/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// import { Octokit } from '@octokit/rest'

// const octokit = new Octokit()

// const run = async () => {
// const res = await octokit.repos.getLatestRelease({
// owner: 'FiloSottile',
// repo: 'mkcert'
// })
// console.log(res.data.assets)
// }
import { GithubDownloader } from '../mkcert/downloader'
// eslint-disable-next-line prettier/prettier
;

;(async () => {
const data = await GithubDownloader.create().getAssetInfo()
console.log(data)
})()
13 changes: 0 additions & 13 deletions test/index.ts

This file was deleted.

0 comments on commit ff9b411

Please sign in to comment.