Skip to content

Instantly share code, notes, and snippets.

@daqi
Created July 17, 2022 03:39
Show Gist options
  • Save daqi/b9d18a1229d13f5b539abd4b915669be to your computer and use it in GitHub Desktop.
Save daqi/b9d18a1229d13f5b539abd4b915669be to your computer and use it in GitHub Desktop.
UOS 或 deepin 打包流程
// UOS 或 deepin 打包流程
// 参考 https://www.vvave.net/archives/how-to-build-a-debian-series-distros-installation-package.html
// sudo apt-get install dh-make
// sudo apt-get install build-essential
const fs = require('fs-extra');
const path = require('path');
const { spawn } = require('child_process');
const globby = require('globby');
const appid = 'com.netease.youdaonote';
const arch = 'amd64';
const cwd = process.cwd();
const run = (cmd, cwd) => {
const chunks = cmd.split(' ');
return new Promise((rz, rj) => {
const childProcess = spawn(chunks.shift(), chunks, { stdio: 'inherit', shell: true, cwd: cwd });
childProcess.on('error', (code) => {
rj(code);
});
childProcess.on('close', (code) => {
rz();
});
});
};
const getVersion = async () => {
return (await fs.readJson(path.join(cwd, 'package.json'))).version;
};
const setInfo = async (file, version) => {
await fs.writeJSON(
file,
{
appid: appid,
name: '有道云笔记',
version: version,
arch: [arch],
permissions: {
autostart: false,
notification: false,
trayicon: false,
clipboard: false,
account: false,
bluetooth: false,
camera: false,
audio_record: false,
installed_apps: false,
},
},
{ spaces: 4 }
);
};
const desktop = `[Desktop Entry]
Categories=Utility;
Type=Application
Name=YoudaoNote
Name[zh_CN]=有道云笔记
Comment=YoudaoNote startup script
Exec="/opt/apps/${appid}/files/ynote-desktop" %f
Icon=${appid}
Terminal=false`;
const setApplications = async (dir) => {
await fs.mkdirp(dir);
await fs.writeFile(path.join(dir, `${appid}.desktop`), desktop);
};
const setIcons = async (dir) => {
for (let d of [16, 24, 32, 48, 128, 256, 512]) {
const iconName = `${d}x${d}`;
await fs.mkdirp(path.join(dir, `/${iconName}/apps/`));
await fs.copy(
path.join(cwd, `resources/icons/${iconName}.png`),
path.join(dir, `/${iconName}/apps/${appid}.png`)
);
}
await fs.mkdirp(path.join(dir, `/scalable/apps/`));
await fs.copy(path.join(cwd, `resources/icon.svg`), path.join(dir, `/scalable/apps/${appid}.svg`));
};
const rewriteControl = async (file) => {
let controlContent = await fs.readFile(file, 'utf-8');
controlContent = controlContent.replace('Section: unknown', 'Section: utils');
controlContent = controlContent.replace('<insert the upstream URL, if relevant>', 'https://note.youdao.com/');
controlContent = controlContent.replace(
'<insert up to 60 chars description>\n <insert long description, indented with spaces>',
'The Youdao Note'
);
await fs.writeFile(file, controlContent, 'utf-8');
};
const rewriteRules = async (file) => {
let rulesContent = await fs.readFile(file, 'utf-8');
rulesContent = rulesContent.replace('#export DH_VERBOSE = 1', 'export DH_VERBOSE = 1');
rulesContent = rulesContent.replace(
'dh $@',
`dh $@\n
override_dh_auto_build:
override_dh_shlibdeps:
override_dh_strip: # 不去除符号文件和调试信息 (strip 操作)
override_dh_strip_nondeterminism: # 不去除多余文本信息
override_dh_installchangelogs: # 不包含安装修改日志
override_dh_installdocs: # 不包含安装文档
override_dh_md5sums: # 不生成 MD5 校验文件
`
);
await fs.writeFile(file, rulesContent, 'utf-8');
};
const writeInstall = async (file) => {
await fs.writeFile(file, `${appid}/ /opt/apps`, 'utf-8');
};
const writePostinst = async (file) => {
await fs.writeFile(
file,
`#!/bin/bash\n
# 修改 chrome-sandbox 可执行
if [ -d /opt/apps/${appid}/ ]; then
chmod 4755 /opt/apps/${appid}/files/chrome-sandbox
if [ $? -eq 0 ];then
exit 0
else
exit 1
fi
fi
`
);
};
const getFile = async (file) => {
return (await globby(file, { onlyFiles: true, deep: 1 }))[0];
};
const getDir = async (dir) => {
return (await globby(dir, { onlyDirectories: true, deep: 1 }))[0];
};
const main = async () => {
const version = await getVersion();
const dir = `${appid}-${version}`;
const dist = path.join(cwd, 'releases');
const root = path.join(dist, dir);
const pkgPath = path.join(root, appid);
await fs.remove(root);
await fs.mkdirp(pkgPath);
// info
await setInfo(path.join(pkgPath, 'info'), version);
// entries
const entriesPath = path.join(pkgPath, 'entries');
// entries/applications
await setApplications(path.join(entriesPath, 'applications'));
// entries/icons
await setIcons(path.join(entriesPath, 'icons/hicolor'));
// files
await fs.copy(await getDir(path.join(dist, `*-unpacked`)), path.join(pkgPath, 'files'));
// dh_make
await run('export DEBFULLNAME=netease && dh_make --createorig -s -n -y -e [email protected]', root);
// debian
const debianPath = path.join(root, 'debian');
// remove useless file
await run('rm *.ex *.EX README* *.docs', debianPath);
// debian/control
await rewriteControl(path.join(debianPath, 'control'));
// debian/rules
await rewriteRules(path.join(debianPath, 'rules'));
// debian/install
await writeInstall(path.join(debianPath, 'install'));
// debian/postinst
await writePostinst(path.join(debianPath, 'postinst'));
// dpkg-buildpackage
await run('fakeroot dpkg-buildpackage -us -uc -b -tc', root);
// log files
console.log(await getFile(path.join(dist, `${appid}*.deb`)));
// deb files
// const debPath = await getFile(path.join(dist, `${appid}*.deb`));
// sign
// await run(`deepin-elf-sign-deb ${debPath}`, dist);
// const signeddebPath = await getFile(path.join(dist, `signed_deb/${appid}*.deb`));
// await run(`deepin-deb-verify ${signeddebPath}`, dist);
};
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment