diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..5887b50 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +output +replacement +demo +*.md diff --git a/.gitignore b/.gitignore index 5def8e9..46c228d 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,14 @@ generate/* !generate/tpl !generate/*.sh !generate/*.xml +!generate/*.md +!generate/dictReplace.txt lang-replacement # godiff* # transfer* + +output/* +!output/*.sh +!output/.cache +!output/.cache/Dockerfile +node_modules \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 4f5fad7..fea1ae6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -26,18 +26,18 @@ RUN apk --update add \ WORKDIR /generate RUN wget https://hub.fastgit.org/rinetd/transfer/releases/download/v1.0.2/transfer-v1.0.2-linux-amd64.tar.gz; \ tar -zxf transfer-v1.0.2-linux-amd64.tar.gz && rm -f transfer-v1.0.2-linux-amd64.tar.gz +RUN wget https://hub.fastgit.org/covrom/xml2json/releases/download/1.0/xml2json; chmod +x xml2json COPY --from=builder /src/lang-replacement /generate COPY --from=builder /src/godiff /generate ADD ./generate/tpl/ /generate/tpl/ ADD ./generate/gitdiff.sh /generate +ADD ./generate/dictReplace.txt /generate ADD ./entry.sh /generate RUN find /generate # EXPOSE 80 ENV GENERATE_REPO="https://gitee.com/g-devops/fk-portainer" \ - GENERATE_BRANCH="br-v29-lang" \ GENERATE_OUTPUT="portainer_zh.xml" \ - REPLACE_REPO="https://gitee.com/g-devops/fk-portainer" \ - REPLACE_BRANCH="release/2.9" \ - EXEC_TYPE="GENERATE" + CMP1="2.9.1" \ + CMP2="origin/br-lang2" ENTRYPOINT /generate/entry.sh diff --git a/README.md b/README.md index a722cbd..2acd770 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,57 @@ - Konga v0.14.9 全支持 - Portainer v2.9.0 半汉化(docker+porainer部分) -## Dev +## 操作说明 + +- pt >> infrastlabs/portainer-cn:latest #基于官方v2.9.1, 生成portainer-cn汉化版镜像 +- registry.cn-shenzhen.aliyuncs.com/infrastlabs/lang-replacement + - dict #字典生成 + - cache #node_modules @v291 + - replace,latest #汉化程序+Node构建 >> 生成public.tar.gz + +**汉化(容器)** + +```bash +# choice1: 直接使用汉化的容器(基于官方v2.9.1, 替换/public) +docker run -it --rm --net=host -v /var/run/docker.sock:/var/run/docker.sock registry.cn-shenzhen.aliyuncs.com/infrastlabs/portainer-cn + +# choice2: 生成public.tar.gz, 手动挂载到容器内使用 +# choice2_step1: 容器运行(node环境: 替换后 直接构建输出public.tar.gz) +$ docker run -it --rm -v $(pwd)/output:/output registry.cn-shenzhen.aliyuncs.com/infrastlabs/lang-replacement +# choice2_step1: 挂载/public目录来使用 +tar -zxf public.tar.gz +docker run -it --rm --net=host -v /var/run/docker.sock:/var/run/docker.sock -v $(pwd)/public:/public portainer/portainer-ce:2.9.1-alpine +``` + +**汉化(二进制用法)** 二进制运行替换后,手工build前端工程 + +```bash +# step1: 二进制运行替换 +# headless @ barge in .../lang-replacement/generate |15:53:12 |dev U:1 ?:2 ✗| +$ ./lang-replacement ./portainer_zh.xml $(pwd)/portainer/app +... +i= 49 portainer/views/users/edit/user.html +(replace)j= 0 {Change user password} > {修改密码} +Replace-Copied 4325 bytes, backdir: /_ext/working/_ct/lang-replacement/generate/portainer/app/.lang-replacement/portainer/views/users/edit/user.html! +i= 50 portainer/views/users/users.html +(replace)j= 0 {Add a new user} > {添加用户} +(replace)j= 1 {Users} > {用户管理} +Replace-Copied 7171 bytes, backdir: /_ext/working/_ct/lang-replacement/generate/portainer/app/.lang-replacement/portainer/views/users/users.html! +FINISH! + +# step2: 基于上1步替换后的源码, 手工build前端工程(Portainer需要在源码层做汉化替换) +# ... +``` + +**生成汉化字典** + +```bash +# headless @ barge in .../_ct/lang-replacement |14:42:10 |dev U:1 ✗| #dindMnt +$ docker run -it --rm -v $(pwd)/output:/output registry.cn-shenzhen.aliyuncs.com/infrastlabs/lang-replacement:generate + +``` + +## Dev开发说明 ```bash # headless @ barge in .../_ct/lang-replacement |11:39:37 |master ↑2 U:1 ?:1 ✗| @@ -25,8 +75,9 @@ $ go build -o godiff -x -v -ldflags "-s -w $flags" ./diff/main.go # -rwxr-xr-x 1 headless headless 2.6M 10月 9 10:09 main00* ``` -## Replacement模版生成 +**Replacement模版生成** +```bash TODO: git diff 锁定到行? > tpl > Replace指定行 **Portainer汉化** @@ -40,26 +91,15 @@ TODO: git diff 锁定到行? > tpl > Replace指定行 - app/edge https://www.bejson.com/xml2json/ +``` -## Use +**buildPortainer** ```bash -# 生成汉化字典 -# headless @ barge in .../_ct/lang-replacement |14:42:10 |dev U:1 ✗| #dindMnt -$ docker run -it --rm -v /mnt/data/$(pwd)/output:/output registry.cn-shenzhen.aliyuncs.com/infrastlabs/lang-replacement - -# 汉化 -# headless @ barge in .../lang-replacement/generate |15:53:12 |dev U:1 ?:2 ✗| -$ ./lang-replacement ./portainer_zh.xml $(pwd)/portainer/app -... -i= 49 portainer/views/users/edit/user.html -(replace)j= 0 {Change user password} > {修改密码} -Replace-Copied 4325 bytes, backdir: /_ext/working/_ct/lang-replacement/generate/portainer/app/.lang-replacement/portainer/views/users/edit/user.html! -i= 50 portainer/views/users/users.html -(replace)j= 0 {Add a new user} > {添加用户} -(replace)j= 1 {Users} > {用户管理} -Replace-Copied 7171 bytes, backdir: /_ext/working/_ct/lang-replacement/generate/portainer/app/.lang-replacement/portainer/views/users/users.html! -FINISH! +# https://www.cnblogs.com/ccti7/p/13956678.html +# npm install image-webpack-loader --save-dev +yarn add image-webpack-loader -D +yarn add image-webpack-loader -g ``` @@ -68,3 +108,4 @@ FINISH! - https://github.com/jsonljd/konga-lang-plugin - http://www.zzvips.com/article/167183.html - https://blog.csdn.net/qiuyoujie/article/details/79289181 + diff --git a/custom.md b/custom.md new file mode 100644 index 0000000..85ef908 --- /dev/null +++ b/custom.md @@ -0,0 +1,38 @@ + +**dict/public.tar.gz** + +```bash +# dict生成 +# ENV GENERATE_REPO="https://gitee.com/g-devops/fk-portainer" \ +# GENERATE_OUTPUT="portainer_zh.xml" \ +# CMP1="2.9.1" \ +# CMP2="origin/br-lang2" +docker run -it --rm -e CMP1=2.9.1 -e CMP2=origin/br-lang3 -v /mnt/data/$(pwd)/output:/output registry.cn-shenzhen.aliyuncs.com/infrastlabs/lang-replacement:dict + + +# xml2json +# wget https://hub.fastgit.org/covrom/xml2json/releases/download/1.0/xml2json +cat portainer_zh.xml |./xml2json |jq + +``` + +**publicMount** + +```bash +# barge: 生成public.tar.gz +# ENV \ +# REPO="https://gitee.com/g-devops/fk-portainer" \ +# # BRANCH="release/2.9" \ +# TAG="2.9.1" + +# TAG=2.9.0 +docker run -it --rm -e BRANCH=sam-custom -v /mnt/data/$(pwd)/output:/output registry.cn-shenzhen.aliyuncs.com/infrastlabs/lang-replacement:replace + + + +# tar -zxf public.tar.gz +public=/mnt/data/$(pwd)/output/portainer/dist/public +docker run -it --rm --net=host -v /var/run/docker.sock:/var/run/docker.sock -v $public:/public portainer/portainer-ce:2.9.1-alpine + + +``` diff --git a/entry.sh b/entry.sh index 5a446a1..ea2d2cb 100755 --- a/entry.sh +++ b/entry.sh @@ -1,15 +1,36 @@ #!/bin/bash -outPath="/output" && mkdir -p $outPath -# if EXEC_TYPE="GENERATE" -# $AUTH -git clone -b $GENERATE_BRANCH $GENERATE_REPO srcGen -export SOURCE=srcGen/app -export CMP1=055c57 -export CMP2=br-v29-lang -export OUTPUT=$outPath/$GENERATE_OUTPUT -./gitdiff.sh +# $AUTH #-b $GENERATE_BRANCH +# TODO /output/.cache/pt0_dict +mkdir -p /output/.cache; srcGenerate=/output/.cache/pt0_dict +# git clone $GENERATE_REPO $srcGenerate #each newDir, just normal clone. +# repo +function getRepo(){ + errExit(){ + echo "$1" + exit 1 + } + if [ ! -d $srcGenerate ]; then + git clone $GENERATE_REPO $srcGenerate #--depth=1 + else + cd $srcGenerate; + git fetch + # if both tag: + git fetch origin tag $CMP1 + git fetch origin tag $CMP2 + fi +} +getRepo + -cat $OUTPUT |wc -# SOURCE=srcReplace +outPath="/output" && mkdir -p $outPath +# export CMP1=055c57 +# export CMP2=br-lang2 +export SOURCE=$srcGenerate/app +export OUTPUT=$outPath/$GENERATE_OUTPUT +/generate/gitdiff.sh +# view +cat $OUTPUT |wc; tail -30 $OUTPUT +# /generate/transfer -f -s $OUTPUT -t /tmp/view.json; cat /tmp/view.json |jq #tranferErr: got "null" +cat $OUTPUT |/generate/xml2json |jq diff --git a/generate/dictReplace.txt b/generate/dictReplace.txt new file mode 100644 index 0000000..f6e9938 --- /dev/null +++ b/generate/dictReplace.txt @@ -0,0 +1,13 @@ +| +| +| +| +| + +| +| +| + + + + diff --git a/generate/gen_portainer.sh b/generate/gen_portainer.sh index c3b33f7..74c738a 100644 --- a/generate/gen_portainer.sh +++ b/generate/gen_portainer.sh @@ -8,7 +8,8 @@ BRANCH="br-v29-lang" # export CMP1=055c57 # export CMP2=origin/br-v29-lang -export SOURCE="/_ext/bbox/_ee/fk-portainer/app" +export SOURCE="/_ext/working/_ct/fk-portainer/app" +# export SOURCE="/_ext/bbox/_ee/fk-portainer/app" export CMP1=604f2823428aa26401b5b0f1ba118eb494325edb export CMP2=br-lang2 #origin/br-v29-lang # export SOURCE="portainer/app" diff --git a/generate/gitdiff.sh b/generate/gitdiff.sh index ec9a42c..0fa330d 100755 --- a/generate/gitdiff.sh +++ b/generate/gitdiff.sh @@ -116,3 +116,18 @@ cat $tmp/root.txt > $tmp/root.json # touch $OUTPUT #if notExist, transfer err (in alpine) $cur/transfer -f -s $tmp/root.json -t $OUTPUT # rm -rf $tmp + +function dictReplace(){ + echo "==[dictReplace]===============" + cat $cur/dictReplace.txt |grep -v "^#" |grep -v "^$" | while read one; do + # echo $one + f1=$(echo $one |cut -d'|' -f1) + f2=$(echo $one |cut -d'|' -f2) + f1=$(echo $f1 |sed "s/\[/\\\[/g" |sed "s/\!/\\\!/g" |sed "s/\]/\\\]/g") + f2=$(echo $f2 |sed "s/\[/\\\[/g" |sed "s/\!/\\\!/g" |sed "s/\]/\\\]/g") + echo "$f1"; echo "$f2"; echo "" + + sed -i "s^$f1^$f2^g" $OUTPUT #$cur/portainer_zh.xml + done +} +dictReplace \ No newline at end of file diff --git a/generate/portainer_zh.xml b/generate/portainer_zh.xml index 11640aa..8b1b05a 100644 --- a/generate/portainer_zh.xml +++ b/generate/portainer_zh.xml @@ -135,7 +135,7 @@ - + @@ -143,7 +143,10 @@ - + + + + docker/views/containers/containers.html @@ -205,7 +208,10 @@ - + + + + docker/views/events/events.html @@ -215,6 +221,10 @@ + + + + docker/views/images/images.html @@ -259,7 +269,7 @@ - + @@ -271,7 +281,10 @@ - + + + + docker/views/networks/networks.html @@ -339,7 +352,10 @@ - + + + + docker/views/volumes/volumes.html @@ -450,7 +466,10 @@ - + + + + portainer/views/registries/registries.html @@ -488,7 +507,7 @@ - + diff --git a/generate/rep_portainer.sh b/generate/rep_portainer.sh deleted file mode 100644 index c2ec23c..0000000 --- a/generate/rep_portainer.sh +++ /dev/null @@ -1,8 +0,0 @@ -cur=$(cd "$(dirname "$0")"; pwd) -cd $cur - -REPO="https://gitee.com/g-devops/fk-portainer" -BRANCH="release/2.9" -# git clone --depth=1 -b $BRANCH $REPO portainer - -./lang-replacement ./portainer_zh.xml ./portainer/app diff --git a/generate/test.md b/generate/test.md new file mode 100644 index 0000000..d8528e7 --- /dev/null +++ b/generate/test.md @@ -0,0 +1,8 @@ + +```bash +headless @ barge in .../lang-replacement/generate |17:31:51 |dev U:3 ?:3 ✗| +$ cat t1.txt |sed "s^<\!\[CDATA\[^bb/^g" +bb/ +# $ cat t1.txt +> go源码编译/jqEnv >> 运行时:Clone代码_br-lang2生成dict (entry/gitdiff.sh) + img="lang-replacement:dict" #v1-generate + docker build $cache $pull -t $repo/$ns/$img -f Dockerfile . + # push + docker push $repo/$ns/$img + # barge=/mnt/data/ ## dind: out-binary + docker run -it --rm --entrypoint=bash -v $barge$(pwd)/generate:/mnt $repo/$ns/$img -c "ls -lh /mnt/; cp -a transfer godiff lang-replacement xml2json /mnt/; ls -lh /mnt/" + ;; + cache) #node_modules @v291 + img="lang-replacement:cache" #v1-generate + cd output/.cache; docker build $cache $pull -t $repo/$ns/$img -f Dockerfile . + docker push $repo/$ns/$img + ;; + pt) #在上一步基础上直接生成CN版 portainer-ce镜像. + img="portainer-cn:latest" #-v291 + cd replacement; docker build $cache $pull -t $repo/$ns/$img -f pt.Dockerfile . + docker push $repo/$ns/$img + ;; + slim) #*) >> node-slim + img="lang-replacement:replace-slim" + cd replacement; docker build $cache $pull -t $repo/$ns/$img -f Dockerfile . #cd replacement + docker push $repo/$ns/$img + ;; + *) #./replacement/Dockerfile >> Node环境+lang_placement+node_modules >> 运行时: Clone发版的代码, 替换CN, npm构建生成public.tar.gz + img="lang-replacement:replace" #v1-generate + cd replacement; docker build $cache $pull -t $repo/$ns/$img -f Dockerfile.alpine . #cd replacement + docker push $repo/$ns/$img + # latest + img2="lang-replacement:latest" + docker tag $repo/$ns/$img docker push $repo/$ns/$img2 + docker push $repo/$ns/$img2 + ;; +esac -# dind: out-binary -# barge=/mnt/data/ -docker run -it --rm --entrypoint=bash -v $barge$(pwd)/generate:/mnt $repo/$ns/$img -c "ls -lh /mnt/; cp -a transfer godiff lang-replacement /mnt/; ls -lh /mnt/" diff --git a/output/.cache/Dockerfile b/output/.cache/Dockerfile new file mode 100644 index 0000000..20c7f61 --- /dev/null +++ b/output/.cache/Dockerfile @@ -0,0 +1,2 @@ +FROM scratch +ADD ./node_modules /.cache/node_modules \ No newline at end of file diff --git a/output/dev_clone.sh b/output/dev_clone.sh new file mode 100644 index 0000000..1b0f481 --- /dev/null +++ b/output/dev_clone.sh @@ -0,0 +1,29 @@ + +REPO="https://gitee.com/g-devops/fk-portainer" +# BRANCH="release/2.9" +TAG="2.9.0" #TAG + +errExit(){ + echo "$1" + exit 1 +} +test -z "$BRANCH" && test -z "$TAG" && errExit "BRANCH/TAG both emp, must set one" +if [ ! -z "$BRANCH" ]; then + # ; git pull + test -d pt0 && (cd pt0; git fetch; git checkout origin/$BRANCH) || git clone -b $BRANCH $REPO pt0 #--depth=1 +else + # test -z "$BRANCH" && BRANCH=$TAG #use tag + # -b "br-$TAG" + test -d pt0 && (cd pt0; git fetch origin tag $TAG; git checkout $TAG) || git clone -b $TAG $REPO pt0 #--depth=1 +fi + + +echo building...; sleep 10 +# REPLACE +mkdir -p .cache/node_modules +rm -rf portainer0; cp -a pt0 portainer0 +cd portainer0 + rm -rf node_modules; ln -s ../.cache/node_modules .; + yarn config set registry https://registry.npm.taobao.org -g + yarn config set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass -g + yarn install #imageUtils's deps hand breadIns; #395M diff --git a/replacement/.dockerignore b/replacement/.dockerignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/replacement/.dockerignore @@ -0,0 +1 @@ +node_modules diff --git a/replacement/Dockerfile b/replacement/Dockerfile new file mode 100644 index 0000000..2283659 --- /dev/null +++ b/replacement/Dockerfile @@ -0,0 +1,52 @@ +FROM registry.cn-shenzhen.aliyuncs.com/infrastlabs/lang-replacement:dict as bins +FROM registry.cn-shenzhen.aliyuncs.com/infrastlabs/lang-replacement:cache as cache + +# ref: dvp-ci-mgr.ui-frontend +# FROM node:10.15.0-alpine AS builder + # ref: docs-devops_vuepress + # node:14.13.1-alpine #39.36 MB + # node:14.13.1-stretch-slim #57.83 MB +# FROM node:14.13.1-alpine AS builder +FROM node:14.13.1-stretch-slim AS builder + +# RUN domain="mirrors.aliyun.com" \ +# && echo "http://$domain/alpine/v3.8/main" > /etc/apk/repositories \ +# && echo "http://$domain/alpine/v3.8/community" >> /etc/apk/repositories \ +# && apk add git bash curl wget jq +# portainer: yarn install +# RUN apk add autoconf libtool libpng automake gcc +RUN domain="mirrors.163.com" \ + && echo "deb http://$domain/debian/ stretch main contrib non-free" > /etc/apt/sources.list \ + && echo "deb http://$domain/debian/ stretch-updates main contrib non-free">> /etc/apt/sources.list; \ + \ + echo 'apt update -qq && apt install -yq --no-install-recommends $@ && apt-get clean && rm -rf /var/lib/apt/lists/*; ' > /usr/local/bin/apt.sh \ + && chmod +x /usr/local/bin/apt.sh +RUN apt.sh \ git bash curl wget jq libpng* + +RUN \ + # npm + npm -v; \ + npm config set registry=https://registry.npm.taobao.org -g; \ + npm config set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass -g; \ + # npm install -g yarn #installed + # grunt + npm install -g grunt-cli; \ + grunt -h; \ + # yarn + yarn -v; \ + yarn config set registry https://registry.npm.taobao.org -g; \ + yarn config set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass -g + +# TODO: node_mods from res_repo +# ADD ./node_modules /.cache/node_modules +COPY --from=cache /.cache/node_modules /.cache/node_modules +ADD ./entry.sh /entry.sh +ADD ./conf/webpack.production.js /conf/webpack.production.js +ADD ./conf/gruntfile.js /conf/gruntfile.js +COPY --from=bins /generate/lang-replacement /usr/local/bin/ +WORKDIR /output + +# VOLUME ["/data"] +# EXPOSE 8080 +ENTRYPOINT ["/entry.sh"] +# RUN apk add libpng \ No newline at end of file diff --git a/replacement/Dockerfile.alpine b/replacement/Dockerfile.alpine new file mode 100644 index 0000000..1b9eb19 --- /dev/null +++ b/replacement/Dockerfile.alpine @@ -0,0 +1,48 @@ +FROM registry.cn-shenzhen.aliyuncs.com/infrastlabs/lang-replacement:dict as bins +FROM registry.cn-shenzhen.aliyuncs.com/infrastlabs/lang-replacement:cache as cache + +# ref: dvp-ci-mgr.ui-frontend +# FROM node:10.15.0-alpine AS builder +# ref: docs-devops_vuepress +FROM node:14.13.1-alpine AS builder +MAINTAINER sam + +RUN domain="mirrors.aliyun.com" \ +&& echo "http://$domain/alpine/v3.8/main" > /etc/apk/repositories \ +&& echo "http://$domain/alpine/v3.8/community" >> /etc/apk/repositories \ +&& apk add git bash curl wget jq +# portainer: yarn install +# RUN apk add autoconf libtool libpng automake gcc + +RUN \ + # npm + npm -v; \ + npm config set registry=https://registry.npm.taobao.org -g; \ + npm config set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass -g; \ + # npm install -g yarn #installed + # grunt + npm install -g grunt-cli; \ + grunt -h; \ + # yarn + yarn -v; \ + yarn config set registry https://registry.npm.taobao.org -g; \ + yarn config set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass -g + +# TODO: node_mods from res_repo +# ADD ./node_modules /.cache/node_modules +COPY --from=cache /.cache/node_modules /.cache/node_modules +ADD ./entry.sh /entry.sh +ADD ./conf/webpack.production.js /conf/webpack.production.js +ADD ./conf/gruntfile.js /conf/gruntfile.js +COPY --from=bins /generate/lang-replacement /usr/local/bin/ +WORKDIR /output + +ENV \ + REPO="https://gitee.com/g-devops/fk-portainer" \ + # BRANCH="release/2.9" \ + TAG="2.9.1" + +# VOLUME ["/data"] +# EXPOSE 8080 +ENTRYPOINT ["/entry.sh"] +RUN apk add libpng \ No newline at end of file diff --git a/replacement/conf/gruntfile.js b/replacement/conf/gruntfile.js new file mode 100644 index 0000000..f637395 --- /dev/null +++ b/replacement/conf/gruntfile.js @@ -0,0 +1,279 @@ +var os = require('os'); +var loadGruntTasks = require('load-grunt-tasks'); +const webpackDevConfig = require('./webpack/webpack.develop'); +const webpackProdConfig = require('./webpack/webpack.production'); +const webpackTestingConfig = require('./webpack/webpack.testing'); + +var arch = os.arch(); +if (arch === 'x64') arch = 'amd64'; + +var portainer_data = '${PORTAINER_DATA:-/tmp/portainer}'; +var portainer_root = process.env.PORTAINER_PROJECT ? process.env.PORTAINER_PROJECT : process.env.PWD; + +module.exports = function (grunt) { + loadGruntTasks(grunt, { + pattern: ['grunt-*', 'gruntify-*'], + }); + + grunt.initConfig({ + root: 'dist', + distdir: 'dist/public', + binaries: { + dockerLinuxVersion: '19.03.13', + dockerWindowsVersion: '19-03-12', + dockerLinuxComposeVersion: '1.27.4', + dockerWindowsComposeVersion: '1.28.0', + dockerComposePluginVersion: '2.0.0-beta.6', + helmVersion: 'v3.6.3', + komposeVersion: 'v1.22.0', + kubectlVersion: 'v1.18.0', + }, + config: gruntfile_cfg.config, + env: gruntfile_cfg.env, + src: gruntfile_cfg.src, + clean: gruntfile_cfg.clean, + eslint: gruntfile_cfg.eslint, + shell: gruntfile_cfg.shell, + copy: gruntfile_cfg.copy, + webpack: gruntfile_cfg.webpack, + }); + + grunt.registerTask('lint', ['eslint']); + + grunt.registerTask('build:server', [ + // 'shell:build_binary:linux:' + arch, + // 'shell:download_docker_binary:linux:' + arch, + // 'shell:download_docker_compose_binary:linux:' + arch, + // 'shell:download_helm_binary:linux:' + arch, + // 'shell:download_kompose_binary:linux:' + arch, + // 'shell:download_kubectl_binary:linux:' + arch, + ]); + + grunt.registerTask('build:client', ['config:dev', 'env:dev', 'webpack:dev']); + + grunt.registerTask('build', ['build:server', 'build:client', 'copy:assets']); + + grunt.registerTask('start:server', ['build:server', 'copy:assets', 'shell:run_container']); + + grunt.registerTask('start:localserver', ['shell:build_binary:linux:' + arch, 'shell:run_localserver']); + + grunt.registerTask('start:client', ['shell:install_yarndeps', 'config:dev', 'env:dev', 'webpack:devWatch']); + + grunt.registerTask('start', ['start:server', 'start:client']); + + grunt.registerTask('start:toolkit', ['start:localserver', 'start:client']); + + grunt.task.registerTask('release', 'release::', function (p = 'linux', a = arch) { + grunt.task.run([ + 'config:prod', + 'env:prod', + 'clean:all', + 'copy:assets', + 'shell:build_binary:' + p + ':' + a, + 'shell:download_docker_binary:' + p + ':' + a, + 'shell:download_docker_compose_binary:' + p + ':' + a, + 'shell:download_helm_binary:' + p + ':' + a, + 'shell:download_kompose_binary:' + p + ':' + a, + 'shell:download_kubectl_binary:' + p + ':' + a, + 'webpack:prod', + ]); + }); + + grunt.task.registerTask('devopsbuild', 'devopsbuild:::', function (p, a, env = 'prod') { + grunt.task.run([ + 'config:prod', + `env:${env}`, + 'clean:all', + 'copy:assets', + // 'shell:build_binary_azuredevops:' + p + ':' + a, + // 'shell:download_docker_binary:' + p + ':' + a, + // 'shell:download_docker_compose_binary:' + p + ':' + a, + // 'shell:download_helm_binary:' + p + ':' + a, + // 'shell:download_kompose_binary:' + p + ':' + a, + // 'shell:download_kubectl_binary:' + p + ':' + a, + `webpack:${env}`, + ]); + }); +}; + +/***/ +var gruntfile_cfg = {}; + +gruntfile_cfg.env = { + dev: { + NODE_ENV: 'development', + }, + prod: { + NODE_ENV: 'production', + }, + testing: { + NODE_ENV: 'testing', + }, +}; + +gruntfile_cfg.webpack = { + dev: webpackDevConfig, + devWatch: Object.assign({ watch: true }, webpackDevConfig), + prod: webpackProdConfig, + testing: webpackTestingConfig, +}; + +gruntfile_cfg.config = { + dev: { options: { variables: { environment: 'development' } } }, + prod: { options: { variables: { environment: 'production' } } }, +}; + +gruntfile_cfg.src = { + js: ['app/**/__module.js', 'app/**/*.js', '!app/**/*.spec.js'], + jsTpl: ['<%= distdir %>/templates/**/*.js'], + html: ['index.html'], + tpl: ['app/**/*.html'], + css: ['assets/css/app.css', 'app/**/*.css'], +}; + +gruntfile_cfg.clean = { + server: ['<%= root %>/portainer'], + client: ['<%= distdir %>/*'], + all: ['<%= root %>/*'], +}; + +gruntfile_cfg.eslint = { + src: ['gruntfile.js', '<%= src.js %>'], + options: { configFile: '.eslintrc.yml' }, +}; + +gruntfile_cfg.copy = { + assets: { + files: [], + }, +}; + +gruntfile_cfg.shell = { + build_binary: { command: shell_build_binary }, + build_binary_azuredevops: { command: shell_build_binary_azuredevops }, + download_docker_binary: { command: shell_download_docker_binary }, + download_kompose_binary: { command: shell_download_kompose_binary }, + download_kubectl_binary: { command: shell_download_kubectl_binary }, + download_helm_binary: { command: shell_download_helm_binary }, + download_docker_compose_binary: { command: shell_download_docker_compose_binary }, + run_container: { command: shell_run_container }, + run_localserver: { command: shell_run_localserver, options: { async: true } }, + install_yarndeps: { command: shell_install_yarndeps }, +}; + +function shell_build_binary(p, a) { + var binfile = 'dist/portainer'; + if (p === 'linux') { + return ['if [ -f ' + binfile + ' ]; then', 'echo "Portainer binary exists";', 'else', 'build/build_binary.sh ' + p + ' ' + a + ';', 'fi'].join(' '); + } else { + return [ + 'powershell -Command "& {if (Get-Item -Path ' + binfile + '.exe -ErrorAction:SilentlyContinue) {', + 'Write-Host "Portainer binary exists"', + '} else {', + '& ".\\build\\build_binary.ps1" -platform ' + p + ' -arch ' + a + '', + '}}"', + ].join(' '); + } +} + +function shell_build_binary_azuredevops(p, a) { + return 'build/build_binary_azuredevops.sh ' + p + ' ' + a + ';'; +} + +function shell_run_container() { + return [ + 'docker rm -f portainer', + 'docker run -d -p 8000:8000 -p 9000:9000 -p 9443:9443 -v ' + + portainer_root + + '/dist:/app -v ' + + portainer_data + + ':/data -v /var/run/docker.sock:/var/run/docker.sock:z -v /var/run/docker.sock:/var/run/alternative.sock:z -v /tmp:/tmp --name portainer portainer/base /app/portainer', + ].join(';'); +} + +function shell_run_localserver() { + return './dist/portainer'; +} + +function shell_install_yarndeps() { + return 'yarn'; +} + +function shell_download_docker_binary(p, a) { + var ps = { windows: 'win', darwin: 'mac' }; + var as = { amd64: 'x86_64', arm: 'armhf', arm64: 'aarch64' }; + var ip = ps[p] === undefined ? p : ps[p]; + var ia = as[a] === undefined ? a : as[a]; + var binaryVersion = p === 'windows' ? '<%= binaries.dockerWindowsVersion %>' : '<%= binaries.dockerLinuxVersion %>'; + + return [ + 'if [ -f dist/docker ] || [ -f dist/docker.exe ]; then', + 'echo "docker binary exists";', + 'else', + 'build/download_docker_binary.sh ' + ip + ' ' + ia + ' ' + binaryVersion + ';', + 'fi', + ].join(' '); +} + +function shell_download_docker_compose_binary(p, a) { + var ps = { windows: 'win', darwin: 'mac' }; + var as = { arm: 'armhf', arm64: 'aarch64' }; + var ip = ps[p] || p; + var ia = as[a] || a; + var binaryVersion = p === 'windows' ? '<%= binaries.dockerWindowsComposeVersion %>' : '<%= binaries.dockerLinuxComposeVersion %>'; + + // plugin + if (p === 'linux' && a !== 'amd64') { + if (a === 'arm64') { + ia = 'arm64'; + } + + if (a === 'arm') { + ia = 'armv7'; + } + binaryVersion = '<%= binaries.dockerComposePluginVersion %>'; + } + + return ` + if [ -f dist/docker-compose ] || [ -f dist/docker-compose.exe ] || [ -f dist/docker-compose.plugin ] || [ -f dist/docker-compose.plugin.exe ]; then + echo "Docker Compose binary exists"; + else + build/download_docker_compose_binary.sh ${ip} ${ia} ${binaryVersion}; + fi`; +} + +function shell_download_helm_binary(p, a) { + var binaryVersion = '<%= binaries.helmVersion %>'; + + return [ + 'if [ -f dist/helm ] || [ -f dist/helm.exe ]; then', + 'echo "helm binary exists";', + 'else', + 'build/download_helm_binary.sh ' + p + ' ' + a + ' ' + binaryVersion + ';', + 'fi', + ].join(' '); +} + +function shell_download_kompose_binary(p, a) { + var binaryVersion = '<%= binaries.komposeVersion %>'; + + return [ + 'if [ -f dist/kompose ] || [ -f dist/kompose.exe ]; then', + 'echo "kompose binary exists";', + 'else', + 'build/download_kompose_binary.sh ' + p + ' ' + a + ' ' + binaryVersion + ';', + 'fi', + ].join(' '); +} + +function shell_download_kubectl_binary(p, a) { + var binaryVersion = '<%= binaries.kubectlVersion %>'; + + return [ + 'if [ -f dist/kubectl ] || [ -f dist/kubectl.exe ]; then', + 'echo "kubectl binary exists";', + 'else', + 'build/download_kubectl_binary.sh ' + p + ' ' + a + ' ' + binaryVersion + ';', + 'fi', + ].join(' '); +} diff --git a/replacement/conf/webpack.production.js b/replacement/conf/webpack.production.js new file mode 100644 index 0000000..7204968 --- /dev/null +++ b/replacement/conf/webpack.production.js @@ -0,0 +1,39 @@ +const webpackMerge = require('webpack-merge'); +const commonConfig = require('./webpack.common.js'); + +module.exports = webpackMerge(commonConfig, { + mode: 'production', + // devtool: 'source-map', + module: { + rules: [ + /* { + test: /\.(woff|woff2|eot|ttf|ico)$/, + use: [ + { + loader: 'url-loader', + options: { limit: 25000 }, + }, + ], + }, + { + test: /\.(gif|png|jpe?g|svg)$/i, + use: [ + 'file-loader', + { + loader: 'image-webpack-loader', + options: {}, + }, + ], + }, */ + { + test: /\.(woff|woff2|eot|ttf|svg|ico|png|jpg|gif)$/, + use: [ + { + loader: 'file-loader', + // options: { limit: 25000 } + }, + ], + }, + ], + }, +}); diff --git a/replacement/entry.sh b/replacement/entry.sh new file mode 100755 index 0000000..c7ccc27 --- /dev/null +++ b/replacement/entry.sh @@ -0,0 +1,67 @@ +#!/bin/bash +# cur=$(cd "$(dirname "$0")"; pwd) +# cd $cur + +function npmBuild(){ + cd /output/portainer + + # # npm + # npm -v + # npm config set registry=https://registry.npm.taobao.org -g + # npm config set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass -g + # # npm install -g yarn #installed + # # grunt + # npm install -g grunt-cli + # grunt -h + + # # yarn + # yarn -v + # yarn config set registry https://registry.npm.taobao.org -g + # yarn config set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass -g + # .cache + # mkdir -p /output/.cache/node_modules; rm -rf node_modules; ln -s /output/.cache/node_modules .; + rm -rf node_modules; ln -s /.cache/node_modules .; + # yarn install + + ## grunt build + # grunt build #OK + # npm run build + ## grunt build prod + rm -f webpack/webpack.production.js; cp /conf/webpack.production.js webpack/webpack.production.js + rm -f gruntfile.js; cp /conf/gruntfile.js gruntfile.js + grunt devopsbuild +} + +# repo +function getRepo(){ + errExit(){ + echo "$1" + exit 1 + } + test -z "$BRANCH" && test -z "$TAG" && errExit "BRANCH/TAG both emp, must set one" + if [ ! -z "$BRANCH" ]; then + test -d pt0 && (cd pt0; git fetch -t; git checkout origin/$BRANCH) || (git clone -b $BRANCH $REPO pt0; cd pt0; git checkout origin/$BRANCH) #--depth=1 + else + test -d pt0 && (cd pt0; git fetch origin tag $TAG; git checkout $TAG) || git clone -b $TAG $REPO pt0 #--depth=1 + fi +} +# REPO="https://gitee.com/g-devops/fk-portainer" +# BRANCH="release/2.9" +# TAG="2.9.0" #TAG +# test -d pt0 && (cd pt0; git pull) || git clone --depth=1 -b $BRANCH $REPO pt0 +getRepo + +# dict portainer_zh.xml +curl -O https://gitee.com/g-devops/lang-replacement/raw/dev/generate/portainer_zh.xml + +# REPLACE +rm -rf portainer; cp -a pt0 portainer +# out app/.lang-replacement +lang-replacement ./portainer_zh.xml ./portainer/app +rm -rf .lang-replacement; mv ./portainer/app/.lang-replacement . +# BUILD +npmBuild + +# PACK +cd /output/portainer/dist; tar -zcf ./public.tar.gz public +ls -lh /output/portainer/dist/ \ No newline at end of file diff --git a/replacement/pt.Dockerfile b/replacement/pt.Dockerfile new file mode 100644 index 0000000..32203c1 --- /dev/null +++ b/replacement/pt.Dockerfile @@ -0,0 +1,52 @@ +FROM registry.cn-shenzhen.aliyuncs.com/infrastlabs/lang-replacement:dict as bins +FROM registry.cn-shenzhen.aliyuncs.com/infrastlabs/lang-replacement:cache as cache + +# ref: dvp-ci-mgr.ui-frontend +# FROM node:10.15.0-alpine AS builder +# ref: docs-devops_vuepress +FROM node:14.13.1-alpine AS builder +MAINTAINER sam + +RUN domain="mirrors.aliyun.com" \ +&& echo "http://$domain/alpine/v3.8/main" > /etc/apk/repositories \ +&& echo "http://$domain/alpine/v3.8/community" >> /etc/apk/repositories \ +&& apk add git bash curl wget jq +# portainer: yarn install +# RUN apk add autoconf libtool libpng automake gcc + +RUN \ + # npm + npm -v; \ + npm config set registry=https://registry.npm.taobao.org -g; \ + npm config set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass -g; \ + # npm install -g yarn #installed + # grunt + npm install -g grunt-cli; \ + grunt -h; \ + # yarn + yarn -v; \ + yarn config set registry https://registry.npm.taobao.org -g; \ + yarn config set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass -g + +# TODO: node_mods from res_repo +# ADD ./node_modules /.cache/node_modules +COPY --from=cache /.cache/node_modules /.cache/node_modules +ADD ./entry.sh /entry.sh +ADD ./conf/webpack.production.js /conf/webpack.production.js +ADD ./conf/gruntfile.js /conf/gruntfile.js +COPY --from=bins /generate/lang-replacement /usr/local/bin/ +WORKDIR /output + +# VOLUME ["/data"] +# EXPOSE 8080 +ENTRYPOINT ["/entry.sh"] +RUN apk add libpng + +##################### +#just lastStage build +RUN /entry.sh +FROM portainer/portainer-ce:2.9.1-alpine +RUN rm -rf /public +COPY --from=builder /output/portainer/dist/public/ /public/ +RUN ls -lh /public +