From 862c320683b9fce6c815b15c0068ee0962ee5124 Mon Sep 17 00:00:00 2001 From: qinyang <466168951@qq.com> Date: Mon, 18 Dec 2017 15:14:20 +0800 Subject: [PATCH] =?UTF-8?q?log--=E4=BF=AE=E5=A4=8D=E4=B8=80=E4=BA=9Bbug=20?= =?UTF-8?q?(#7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 下载的时候,如果文件已存在,则重命名 && 发布的时候,把对应channel的yml文件转换成json,也上传到oss,用作各客户端获取版本信息 修复windows下,上边框无法resize的问题 --- .rishiqing-deploy.yml | 79 +++++++++++++++++++++++ Gruntfile.js | 17 +++-- download.js | 30 ++++++++- fe/css/core.css | 24 ++++--- fe/scss/core.scss | 8 ++- package.json | 6 +- utils/file/file.js | 61 ++++++++++++++++++ utils/file/fileType.js | 21 +++++++ utils/file/index.js | 138 +++++++++++++++++++++++++++++++++++++++++ 9 files changed, 361 insertions(+), 23 deletions(-) create mode 100644 utils/file/file.js create mode 100644 utils/file/fileType.js create mode 100644 utils/file/index.js diff --git a/.rishiqing-deploy.yml b/.rishiqing-deploy.yml index c2d7c8e..909092e 100644 --- a/.rishiqing-deploy.yml +++ b/.rishiqing-deploy.yml @@ -3,6 +3,7 @@ default: title: 'rishiqing-electron-deploy' # 推送时候的标题,可自定义,默认是rishiqing-deploy nodes: # 定义在哪些环节需要通知 , 在发布的时候,node需要有一些默认值 - 'after-build' # 在所有build执行完之后,通知 + - 'after-convert' # 在所有convert执行之后,通知 - 'resource' # 在所有resource传输完成 - 'file-replace' # 所有fileReplace任务完成 - 'statistics' # 把发布之后的统计结果通过通知发送出来 @@ -16,6 +17,9 @@ default: ia32-beta: build: - 'npm run build-ia32-beta' + convert: + target: package-ia32-beta/beta.yml + dest: package-ia32-beta/beta.json resource: - dist: 'package-ia32-beta' # 资源所在目录 或者 文件路径 ignore: @@ -41,10 +45,23 @@ ia32-beta: bucket: 'rishiqing-client' endpoint: 'http://oss-cn-shenzhen.aliyuncs.com' prefix: 'pc-autoupdate/win/ia32/beta' + - dist: 'package-ia32-beta/beta.json' # 资源所在目录 或者 文件路径 + target: 'beta.json' + upload: # 以下指定上传资源文件要用的方式,如果指定多个,会依次使用上传 + - type: 'aliyunOss' + param: + accessKeyId: ${ALY_OSS_Access_Id} + secretAccessKey: ${ALY_OSS_Access_Key} + bucket: 'rishiqing-client' + endpoint: 'http://oss-cn-shenzhen.aliyuncs.com' + prefix: 'pc-autoupdate/win/ia32/beta' ia32-release: build: - 'npm run build-ia32-release' + convert: + target: package-ia32-release/release.yml + dest: package-ia32-release/release.json resource: - dist: 'package-ia32-release' # 资源所在目录 或者 文件路径 ignore: @@ -70,10 +87,23 @@ ia32-release: bucket: 'rishiqing-client' endpoint: 'http://oss-cn-shenzhen.aliyuncs.com' prefix: 'pc-autoupdate/win/ia32/release' + - dist: 'package-ia32-release/release.json' # 资源所在目录 或者 文件路径 + target: 'release.json' + upload: # 以下指定上传资源文件要用的方式,如果指定多个,会依次使用上传 + - type: 'aliyunOss' + param: + accessKeyId: ${ALY_OSS_Access_Id} + secretAccessKey: ${ALY_OSS_Access_Key} + bucket: 'rishiqing-client' + endpoint: 'http://oss-cn-shenzhen.aliyuncs.com' + prefix: 'pc-autoupdate/win/ia32/release' x64-beta: build: - 'npm run build-x64-beta' + convert: + target: package-x64-beta/beta.yml + dest: package-x64-beta/beta.json resource: - dist: 'package-x64-beta' # 资源所在目录 或者 文件路径 ignore: @@ -99,10 +129,23 @@ x64-beta: bucket: 'rishiqing-client' endpoint: 'http://oss-cn-shenzhen.aliyuncs.com' prefix: 'pc-autoupdate/win/x64/beta' + - dist: 'package-x64-beta/beta.json' # 资源所在目录 或者 文件路径 + target: 'beta.json' + upload: # 以下指定上传资源文件要用的方式,如果指定多个,会依次使用上传 + - type: 'aliyunOss' + param: + accessKeyId: ${ALY_OSS_Access_Id} + secretAccessKey: ${ALY_OSS_Access_Key} + bucket: 'rishiqing-client' + endpoint: 'http://oss-cn-shenzhen.aliyuncs.com' + prefix: 'pc-autoupdate/win/x64/beta' x64-release: build: - 'npm run build-x64-release' + convert: + target: package-x64-release/release.yml + dest: package-x64-release/release.json resource: - dist: 'package-x64-release' # 资源所在目录 或者 文件路径 ignore: @@ -128,10 +171,23 @@ x64-release: bucket: 'rishiqing-client' endpoint: 'http://oss-cn-shenzhen.aliyuncs.com' prefix: 'pc-autoupdate/win/x64/release' + - dist: 'package-x64-release/release.json' # 资源所在目录 或者 文件路径 + target: 'release.json' + upload: # 以下指定上传资源文件要用的方式,如果指定多个,会依次使用上传 + - type: 'aliyunOss' + param: + accessKeyId: ${ALY_OSS_Access_Id} + secretAccessKey: ${ALY_OSS_Access_Key} + bucket: 'rishiqing-client' + endpoint: 'http://oss-cn-shenzhen.aliyuncs.com' + prefix: 'pc-autoupdate/win/x64/release' mac-beta: build: - 'npm run build-beta' + convert: + target: package-beta/beta-mac.yml + dest: package-beta/beta-mac.json resource: - dist: 'package-beta' # 资源所在目录 或者 文件路径 ignore: @@ -158,10 +214,23 @@ mac-beta: bucket: 'rishiqing-client' endpoint: 'http://oss-cn-shenzhen.aliyuncs.com' prefix: 'pc-autoupdate/mac/beta' + - dist: 'package-beta/beta-mac.json' # 资源所在目录 或者 文件路径 + target: 'beta-mac.json' + upload: # 以下指定上传资源文件要用的方式,如果指定多个,会依次使用上传 + - type: 'aliyunOss' + param: + accessKeyId: ${ALY_OSS_Access_Id} + secretAccessKey: ${ALY_OSS_Access_Key} + bucket: 'rishiqing-client' + endpoint: 'http://oss-cn-shenzhen.aliyuncs.com' + prefix: 'pc-autoupdate/mac/beta' mac-release: build: - 'npm run build-release' + convert: + target: package-release/release-mac.yml + dest: package-release/release-mac.json resource: - dist: 'package-release' # 资源所在目录 或者 文件路径 ignore: @@ -180,6 +249,16 @@ mac-release: fileReplace: - dist: 'package-release/release-mac.yml' # 资源所在目录 或者 文件路径 target: 'release-mac.yml' + upload: # 以下指定上传资源文件要用的方式,如果指定多个,会依次使用上传 + - type: 'aliyunOss' + param: + accessKeyId: ${ALY_OSS_Access_Id} + secretAccessKey: ${ALY_OSS_Access_Key} + bucket: 'rishiqing-client' + endpoint: 'http://oss-cn-shenzhen.aliyuncs.com' + prefix: 'pc-autoupdate/mac/release' + - dist: 'package-release/release-mac.json' + target: 'release-mac.json' upload: # 以下指定上传资源文件要用的方式,如果指定多个,会依次使用上传 - type: 'aliyunOss' param: diff --git a/Gruntfile.js b/Gruntfile.js index a51b289..5fce486 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -2,7 +2,7 @@ * @Author: apple * @Date: 2016-02-17 11:06:44 * @Last Modified by: qinyang -* @Last Modified time: 2017-12-16 18:32:12 +* @Last Modified time: 2017-12-18 11:35:52 */ var path = require('path'); @@ -36,7 +36,12 @@ module.exports = function (grunt) { } }, files: [ - {expand: true, src: ['fe/**/*.js'], dest: destPath} + {expand: true, src: ['fe/**/*.js'], dest: destPath}, + {expand: true, src: ['utils/**/*.js'], dest: destPath}, + {expand: true, src: ['native/**/*.js'], dest: destPath}, + {expand: true, src: ['common/**/*.js'], dest: destPath}, + {expand: true, src: 'main.js', dest: destPath}, + {expand: true, src: 'download.js', dest: destPath} ] } }, @@ -84,10 +89,10 @@ module.exports = function (grunt) { // }, mainJs: { files: [ - {expand: true, src: 'main.js', dest: destPath}, - {expand: true, src: 'download.js', dest: destPath}, - {expand: true, src: 'native/*.js', dest: destPath}, - {expand: true, src: 'common/*.js', dest: destPath} + // {expand: true, src: 'main.js', dest: destPath}, + // {expand: true, src: 'download.js', dest: destPath}, + // {expand: true, src: 'native/*.js', dest: destPath}, + // {expand: true, src: 'common/*.js', dest: destPath} ] } }, diff --git a/download.js b/download.js index 39e5ee9..ed7edae 100644 --- a/download.js +++ b/download.js @@ -2,13 +2,16 @@ const electron = require('electron'); const path = require('path'); const packageJson = require('./package.json'); const EVENTS = require('./common/download_event'); +const FileUtil = require('./utils/file'); const BrowserWindow = electron.BrowserWindow; const ipcMain = electron.ipcMain; const app = electron.app; let downloadIdCount = 0; +const DownloadPath = app.getPath('downloads'); // 下载路径 const DownloadItemIdMap = {}; // 缓存下载对象和itemId之间的映射关系 +const DownloadFileNameMap = {}; // 缓存正在现在的文件名,防止某些文件还没下载完成,又下载同一文件名的文件 class Download { constructor () { @@ -42,11 +45,33 @@ class Download { } } + isFileExist (fileName) { + const p = path.join(DownloadPath, fileName); + return FileUtil.isExist(p) || DownloadFileNameMap[fileName]; + } + + generateDownloadFileName (fileName) { + let isExist = this.isFileExist(fileName); + if (!isExist) return fileName; + const extname = path.extname(fileName); + const basename = path.basename(fileName, extname); + + let count = 0; + + while (isExist) { + isExist = this.isFileExist(`${basename}(${++count})${extname}`); + } + return `${basename}(${count})${extname}`; + } + startDownload (item) { + const fileName = this.generateDownloadFileName(item.getFilename()); // 下载项先暂时默认保存到下载路径里,后面需要增加用户修改默认保存路径的功能 - item.setSavePath(path.join(app.getPath('downloads'), item.getFilename())); + item.setSavePath(path.join(DownloadPath, fileName)); item.id = ++downloadIdCount; + item.fileName = fileName; DownloadItemIdMap[item.id] = item; + DownloadFileNameMap[fileName] = true; this.open(); this.webContents.send(EVENTS.Start, { savePath: item.getSavePath(), @@ -54,7 +79,7 @@ class Download { originUrl: item.getURL(), mimeType: item.getMimeType(), hasUserGesture: item.hasUserGesture(), - fileName: item.getFilename(), + fileName: fileName, totalBytes: item.getTotalBytes(), receivedBytes: item.getReceivedBytes(), contentDisposition: item.getContentDisposition(), @@ -98,6 +123,7 @@ class Download { }); } delete DownloadItemIdMap[item.id]; + delete DownloadFileNameMap[item.fileName]; }); } diff --git a/fe/css/core.css b/fe/css/core.css index 238ab48..f9565de 100644 --- a/fe/css/core.css +++ b/fe/css/core.css @@ -837,22 +837,22 @@ body.win #main-iframe { display: inline-block; } -/* line 185, ../scss/core.scss */ +/* line 186, ../scss/core.scss */ .drag-bar-win { display: none; position: absolute; left: 0; - top: 0; + top: 4px; right: 0; - height: 32px; + height: 28px; background: #5A98D4; z-index: 2; } -/* line 192, ../scss/core.scss */ +/* line 193, ../scss/core.scss */ .drag-bar-win .traffic-lights { position: absolute; right: 0; - top: 0; + top: -4px; height: 32px; display: flex; z-index: 1; @@ -861,31 +861,35 @@ body.win #main-iframe { align-items: center; padding: 0 12px; } -/* line 203, ../scss/core.scss */ +/* line 204, ../scss/core.scss */ .drag-bar-win .traffic-lights > span { display: inline-block; height: 12px; width: 12px; } -/* line 207, ../scss/core.scss */ +/* line 208, ../scss/core.scss */ .drag-bar-win .traffic-lights > span img { vertical-align: top; } -/* line 215, ../scss/core.scss */ +/* line 216, ../scss/core.scss */ body.mac .drag-bar-mac { display: block; } /* line 220, ../scss/core.scss */ +body.win { + background: #5A98D4; +} +/* line 222, ../scss/core.scss */ body.win .drag-bar-win { display: block; } -/* line 223, ../scss/core.scss */ +/* line 225, ../scss/core.scss */ body.win .traffic-lights.mac { display: none; } -/* line 226, ../scss/core.scss */ +/* line 228, ../scss/core.scss */ body.win #loading, body.win #alert { top: 32px; } diff --git a/fe/scss/core.scss b/fe/scss/core.scss index 2befbe3..87a4935 100644 --- a/fe/scss/core.scss +++ b/fe/scss/core.scss @@ -182,17 +182,18 @@ body.win { } } } +$bar-win-offset: 4px; .drag-bar-win { display: none; position: absolute; - left: 0; top: 0; right: 0; - height: 32px; + left: 0; top: $bar-win-offset; right: 0; + height: 32px - $bar-win-offset; background: #5A98D4; z-index: 2; .traffic-lights { position: absolute; right: 0; - top: 0; + top: -$bar-win-offset; height: 32px; display: flex; z-index: 1; @@ -217,6 +218,7 @@ body.mac { } } body.win { + background: #5A98D4; .drag-bar-win { display: block; } diff --git a/package.json b/package.json index 7d67510..f86dc4d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rishiqing-electron", - "version": "3.0.3", + "version": "3.0.4", "author": "北京创仕科锐信息技术有限责任公司", "electronVersion": "1.7.9", "main": "main.js", @@ -39,8 +39,10 @@ "dependencies": { "electron-updater": "2.16.3", "handlebars": "4.0.11", + "is-gzip": "2.0.0", "jquery": "2.2.0", "lodash": "4.17.4", + "md5-file": "3.2.3", "module-alias": "2.0.3", "nedb": "1.8.0", "request": "2.72.0", @@ -61,7 +63,7 @@ "grunt-contrib-sass": "^0.9.2", "grunt-contrib-uglify": "git+https://github.com/gruntjs/grunt-contrib-uglify.git#harmony", "grunt-zip": "^0.17.1", - "rishiqing-deploy": "^1.0.2", + "rishiqing-deploy": "^1.0.3", "yargs": "^4.1.0" }, "optionalDependencies": { diff --git a/utils/file/file.js b/utils/file/file.js new file mode 100644 index 0000000..e861ca8 --- /dev/null +++ b/utils/file/file.js @@ -0,0 +1,61 @@ +/* +* @Author: apple +* @Date: 2016-01-15 12:11:54 +* @Last Modified by: qinyang +* @Last Modified time: 2017-12-18 11:43:56 +*/ + +const fs = require('fs'); +const path = require('path'); +const md5File = require('md5-file'); +const isGzip = require('is-gzip'); +const fileType = require('./fileType'); + +class File { + constructor (config) { + this.path = config.path; + this._init(); + } + // public + // 获取扩展名 + // 带点的 + getExtname () { + return this.extname; + } + getExtnameWithoutDot () { + return this.getExtname().replace(/^\./, ''); + } + // 获取名字 + getName () { + return this.name; + } + // 获取文件的MD5值 + getMd5 () { + return md5File.sync(this.path); + } + isGzip () { + return isGzip(fs.readFileSync(this.path)); + } + fileType () { + return fileType[this.extname] || 'other'; + } + rename (newPath) { + fs.renameSync(this.path, newPath); + this.path = newPath; + this._init(); + } + read () { + return fs.readFileSync(this.path, 'utf8'); + } + write (str) { + fs.writeFileSync(this.path, str, 'utf8'); + } + // privite + _init () { + this.extname = path.extname(this.path); + this.name = path.basename(this.path); + } + // static +} + +module.exports = File; diff --git a/utils/file/fileType.js b/utils/file/fileType.js new file mode 100644 index 0000000..c326b67 --- /dev/null +++ b/utils/file/fileType.js @@ -0,0 +1,21 @@ +module.exports = { + '.js': 'js', + '.html': 'html', + '.css': 'css', + '.json': 'json', + '.svg': 'font', + '.eot': 'font', + '.woff2': 'font', + '.ttf': 'font', + '.woff': 'font', + '.jpeg': 'image', + '.jpg': 'image', + '.tiff': 'image', + '.raw': 'image', + '.bmp': 'image', + '.gif': 'image', + '.png': 'image', + '.map': 'map', + '.gz': 'gz', + '.yml': 'yml' +}; diff --git a/utils/file/index.js b/utils/file/index.js new file mode 100644 index 0000000..edef577 --- /dev/null +++ b/utils/file/index.js @@ -0,0 +1,138 @@ +/* +* @Author: apple +* @Date: 2016-01-15 12:11:47 +* @Last Modified by: qinyang +* @Last Modified time: 2017-12-18 11:44:03 +*/ + +const File = require('./file'); +const fs = require('fs'); +const path = require('path'); + +class Index { + constructor (config) { + const isOk = this._isConfigOk(config); + this.file = null; + if (isOk.path) { + this.file = new File(isOk); + } + } + // public + + // 以_开头的方法都是私有方法 privite + // 判断config里的参数是否正确 + _isConfigOk (config) { + let p = ''; + if (!config) return false; + if (typeof config === 'string') { + p = config; + } else if (typeof config === 'object') { + p = config.path; + } + if (typeof p !== 'string') { + return false; + } + this.path = p; + const stat = Index.isExist(p); + if (!stat) { + return false; + } + return {path: p}; + } + static isDirectory (p) { + if (!p || typeof p !== 'string') { + return; + } + if (!Index.isExist(p)) { + return; + } + const pathStates = fs.statSync(p); + return pathStates.isDirectory(); + } + static isFile (p) { + if (!p || typeof p !== 'string') { + return; + } + if (!Index.isExist(p)) { + return; + } + const pathStates = fs.statSync(p); + return pathStates.isFile(); + } + static type (p) { + const isDirectory = Index.isDirectory(p); + const isFile = Index.isFile(p); + if (isDirectory) { + return 'directory'; + } else if (isFile) { + return 'file'; + } + } + // static method + static isExist (p) { + let stat = {}; + try { + stat = fs.statSync(p); + } catch (e) { + return false; + } + return stat; + } + static readFileList (p) { + if (!p || typeof p !== 'string') { + return; + } + if (!Index.isExist(p)) { + return; + } + const fileList = []; + const pathStates = fs.statSync(p); + if (!pathStates.isDirectory()) {// 如果是文件 + const states = fs.statSync(p); + const obj = new Object(); + obj.size = states.size; + obj.name = path.basename(p); + obj.path = p; + const f = new File(obj); + obj.md5 = f.getMd5(); + obj.isGzip = f.isGzip(); + obj.type = f.fileType(); + obj.extname = f.extname; + fileList.push(obj); + return fileList; + } + + + const traverse = function (_p) { + const files = fs.readdirSync(_p); + files.forEach(function (file) { + const states = fs.statSync(path.join(_p, file)); + if (states.isDirectory()) { + traverse(path.join(_p, file)); + } else { + const obj = new Object(); + obj.size = states.size; + obj.name = file; + obj.path = path.join(_p, file); + const f = new File(obj); + + obj.md5 = f.getMd5(); + + obj.isGzip = f.isGzip(); + obj.type = f.fileType(); + obj.extname = f.extname; + + fileList.push(obj); + } + }); + } + traverse(p); + return fileList; + } + + static createFile (file, data, options) { + return fs.writeFileSync(file, data, options); + } +} + +module.exports = Index;