using System.ComponentModel; using System.Data; using System.Text; using MySql.Data.MySqlClient; namespace Tiobon.PublishHelper { public partial class Form_Main : Form { #region 初始化 public Form_Main() { InitializeComponent(); } private void Form_Main_Load(object sender, EventArgs e) { Utility.Init(); Init(); } Thread t_RefreshServer; /// /// 重要:规约要求开发环境必装dev目录下,运维测试必装root目录下 /// private string SelectEnv = string.Empty; /// /// 冗余多开发环境docker地址后缀 /// private string SelectCmdSuffix = string.Empty; private void Init() { lb_Logger.ItemHeight = 16; treeView_Main.ItemHeight = 20; Utility.SendLogHandle += SendLog; Utility.SetStatus += SetStatus; Utility.SetProgressBarValue += SetProgressBar; Utility.SetProgressBarVisible += SetProgressBarVisible; tssl_ServerStatus.Visible = false; tssl_Split3.Visible = false; RefreshTree(); cb_webapi.Checked = Utility.m_OprateLog.Webapi; cb_hfs.Checked = Utility.m_OprateLog.Hfs; cb_job.Checked = Utility.m_OprateLog.Job; cb_rtm.Checked = Utility.m_OprateLog.Rtm; cb_remove.Checked = Utility.m_OprateLog.Remove; cb_build.Checked = Utility.m_OprateLog.Build; cb_web.Checked = Utility.m_OprateLog.Web; cb_pad.Checked = Utility.m_OprateLog.Pad; timer_Main.Start(); if (!string.IsNullOrEmpty(Utility.m_OprateLog.ServerName) && !string.IsNullOrEmpty(Utility.m_OprateLog.HospitalName)) { foreach (TreeNode node in treeView_Main.Nodes) { if (node.Name == Utility.m_OprateLog.ServerName) { foreach (TreeNode nodeItem in node.Nodes) { if (nodeItem.Name == Utility.m_OprateLog.HospitalName) { treeView_Main.SelectedNode = nodeItem; break; } } break; } } } t_RefreshServer = new Thread(new ThreadStart(delegate { RefreshServer(); })); t_RefreshServer.Start(); //SetFont(this); } Font defaultFont = new Font("宋体", 11, FontStyle.Regular); void SetFont(Control control) { control.Font = defaultFont; if (control.HasChildren) { foreach (Control item in control.Controls) { if (item is GroupBox) continue; SetFont(item); } } } //private double m_CpuMax = 0; private double m_MemMax = 0; private double m_DiskMax = 0; private void RefreshServer() { while (!b_Closed) { if (DateTime.Now.Second % 5 == 0) { try { BeginInvoke(new EventHandler(delegate { (bool Success, double Cpu, double MemTotal, double MemUsed, double Disk) res = (false, 0.0, 0.0, 0.0, 0.0); DevServer server = null; var node = treeView_Main.SelectedNode; if (node != null) { if (node.Tag.ToString() != "hospital") { server = Utility.m_DevServers.Where(o => o.Name == node.Name).FirstOrDefault(); } else { server = Utility.m_DevServers.Where(o => o.Name == node.Parent.Name).FirstOrDefault(); } if (server != null) { res = Utility.GetServerStatus(server); } } Color color = System.Drawing.SystemColors.ControlText; if (server != null && res.Success) { var mused = Math.Round(100.0 * res.MemUsed / res.MemTotal, 2); tssl_ServerStatus.Visible = true; tssl_Split3.Visible = true; tssl_ServerStatus.Text = $"{server.Ip}(已用): Cpu {res.Cpu}% Mem {mused}% Disk {res.Disk}%"; //if (res.Cpu > 90 && res.Cpu < 100 && m_CpuMax != res.Cpu) //{ // m_CpuMax = res.Cpu; // Utility.SendLog($"{server.Ip} Cpu使用率过高 {res.Cpu}%"); //} if (mused > 90 && m_MemMax != mused) { m_MemMax = mused; //Utility.SendLog($"{server.Ip} 物理内存使用率过高 {mused}%"); color = Color.Red; } if (res.Disk > 90 && m_DiskMax != res.Disk) { m_DiskMax = res.Disk; //Utility.SendLog($"{server.Ip} 磁盘使用率过高 {res.Disk}%"); color = Color.Red; } tssl_ServerStatus.ForeColor = color; } else { tssl_ServerStatus.ForeColor = color; tssl_ServerStatus.Visible = false; tssl_Split3.Visible = false; } })); } catch { } } System.Threading.Thread.Sleep(1000); } } bool b_Closed = false; private void Form_Main_FormClosing(object sender, FormClosingEventArgs e) { if (b_Closed) return; if (e.CloseReason == CloseReason.UserClosing || e.CloseReason == CloseReason.None) { if (MessageBox.Show("确定关闭发布工具?", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { b_Closed = true; ExitSystem(); } else { e.Cancel = true; } } else { b_Closed = true; ExitSystem(); } } private void ExitSystem() { try { var node = treeView_Main.SelectedNode; if (node != null) { if (node.Tag.ToString() == "hospital") { Utility.m_OprateLog.ServerName = Utility.m_DevServers.Where(o => o.Name == node.Parent?.Name).FirstOrDefault()?.Name; Utility.m_OprateLog.HospitalName = Utility.m_DevServers.Where(o => o.Name == node.Parent?.Name).FirstOrDefault()?.Hospitals?.Where(o => o.Name == node.Name).FirstOrDefault()?.Name; } } timer_Main.Stop(); t_RefreshServer.Abort(); Utility.m_OprateLog.Webapi = cb_webapi.Checked; Utility.m_OprateLog.Hfs = cb_hfs.Checked; Utility.m_OprateLog.Job = cb_job.Checked; Utility.m_OprateLog.Rtm = cb_rtm.Checked; Utility.m_OprateLog.Remove = cb_remove.Checked; Utility.m_OprateLog.Build = cb_build.Checked; Utility.m_OprateLog.Web = cb_web.Checked; Utility.m_OprateLog.Pad = cb_pad.Checked; Utility.SaveOprateLog(); //Environment.Exit(0); } catch { } } private void RefreshTree() { tssl_Dev.Text = $"Dev:Server - {Utility.m_DevServers.Count} Hospital - {Utility.m_DevServers.Sum(o => o.Hospitals.Count)}"; tssl_Publish.Text = $"Pulish:Server - {Utility.m_PublishServers.Count} File - {Utility.m_PublishServers.Sum(o => o.Folders.Sum(f => f.Files.Count))}"; treeView_Main.Nodes.Clear(); Utility.m_DevServers.ForEach(server => { TreeNode tnServer = new TreeNode() { Tag = "server", Name = server.Name, Text = $"{server.Name}" }; server?.Hospitals?.ForEach(hospital => { tnServer.Nodes.Add(new TreeNode() { Tag = "hospital", Name = hospital.Name, Text = $"{hospital.Name}({hospital.DefaultFort})" }); }); treeView_Main.Nodes.Add(tnServer); }); treeView_Main.ExpandAll(); } #endregion #region Tree操作 private bool HasSelectdServer(out DevServer server) { server = null; var node = treeView_Main.SelectedNode; if (node is null || node.Tag.ToString() != "server") return false; server = Utility.m_DevServers.Where(o => o.Name == node.Name).FirstOrDefault(); if (server is null) return false; return true; } private bool HasSelectdHospital(out DevServer server, out Hospital hospital) { server = null; hospital = null; var node = treeView_Main.SelectedNode; if (node is null || node.Tag.ToString() != "hospital") return false; server = Utility.m_DevServers.Where(o => o.Name == node.Parent?.Name).FirstOrDefault(); if (server is null) return false; hospital = server?.Hospitals?.Where(o => o.Name == node.Name).FirstOrDefault(); if (hospital is null) return false; return true; } private void contextMenuStrip_Tree_Opening(object sender, CancelEventArgs e) { if (treeView_Main.SelectedNode == null) return; //选中服务器 if (treeView_Main.SelectedNode.Tag.ToString() == "server") { var server = Utility.m_DevServers.Where(o => o.Name == treeView_Main.SelectedNode.Name).FirstOrDefault(); if (server?.Ip == Utility.m_TestServerIp) { foreach (ToolStripItem item in contextMenuStrip_Tree.Items) { item.Visible = false; } } else { foreach (ToolStripItem item in contextMenuStrip_Tree.Items) { if (item.Name == "tsmi_RemoveLocker" || item.Name == "tsmi_HospitalCreate") { item.Visible = true; } else { item.Visible = false; } } } } else { //选中医院 var server = Utility.m_DevServers.Where(o => o.Name == treeView_Main.SelectedNode.Parent.Name).FirstOrDefault(); if (server?.Ip == Utility.m_TestServerIp) { foreach (ToolStripItem item in contextMenuStrip_Tree.Items) { item.Visible = false; } } else { foreach (ToolStripItem item in contextMenuStrip_Tree.Items) { if (item.Name == "tsmi_RemoveLocker") { item.Visible = false; } else { item.Visible = true; } } } } } private void treeView_Main_AfterSelect(object sender, TreeViewEventArgs e) { Thread t = new Thread(new ThreadStart(delegate { RefreshDocker(); })); t.Start(); } private void RefreshDocker(TreeNode node = null) { try { BeginInvoke(new EventHandler(delegate { if (node == null) node = treeView_Main.SelectedNode; if (node?.Tag.ToString() != "hospital") { return; } var server = Utility.m_DevServers.Where(o => o.Name == node.Parent?.Name).FirstOrDefault(); var hospital = server?.Hospitals?.Where(o => o.Name == node.Name).FirstOrDefault(); if (server is null || hospital is null) return; //获取docker信息 var flag = $"{server.Name} - {hospital.Name} - {hospital.DefaultFort}"; this.gb_Docker.Text = flag; var (Success, Result) = SshHelper.ExcuteCmd(server, DockerCommand.GetDockerStatus(hospital.FileName)); listView_App.Items.Clear(); if (Success) { if (!string.IsNullOrEmpty(Result)) { string[] empties = Result.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < empties.Length; ++i) { string[] items = empties[i].Split(new string[] { "||" }, StringSplitOptions.None); ListViewItem item = new ListViewItem(); item.SubItems[0].Text = items[0]; for (int j = 1; j < items.Length; ++j) item.SubItems.Add(items[j]); listView_App.Items.Add(item); } Utility.SendLog(flag, $"刷新成功"); SelectEnv = hospital.DefaultFort == "600" ? "dev" : "root"; SelectCmdSuffix = SelectEnv == "dev" ? "/compose" : string.Empty; } } else { if (SftpHelper.Exists(server, $"/home/{server.UserName}/ihdis/compose/{hospital.FileName}")) { if (string.IsNullOrEmpty(Result)) { Utility.SendLog(flag, "项目已经停止运行"); } else { Utility.SendLog(flag, Result); } } else { Utility.SendLog(flag, $"医院不存在"); } } })); } catch { } } private void tsmi_HospitalCreate_Click(object sender, EventArgs e) { var node = treeView_Main.SelectedNode; if (node is null) return; DevServer server = null; Hospital hospital = null; //服务器操作 if (node.Tag.ToString() == "server") { server = Utility.m_DevServers.Where(o => o.Name == node.Name).FirstOrDefault(); using (Form_Hospital_Item f = new Form_Hospital_Item(server.Name, "新增")) { f.ShowDialog(); hospital = f.m_Hoipital; } if (!(hospital is null)) { Utility.SaveDevServer(); RefreshTree(); } } else { //医院操作 server = Utility.m_DevServers.Where(o => o.Name == node.Parent?.Name).FirstOrDefault(); hospital = server?.Hospitals?.Where(o => o.Name == node.Name).FirstOrDefault(); if (server is null || hospital is null) return; if (SftpHelper.Exists(server, $"/home/{server.UserName}/ihdis/compose/{hospital.FileName}")) { MessageBox.Show("医院已经存在,不允许重复创建", "提示"); return; } if (SshHelper.InRtmNow()) { MessageBox.Show("正在执行其他命令,请等待!", "提示"); return; } Thread t = new Thread(new ThreadStart(delegate { SshHelper.ExcuteCmdRtm(server, $"cd /home/{server.UserName}/ihdis;sudo bash create-hospital.sh {hospital.FileName} {hospital.DefaultFort} {GetMask(server)};"); RefreshDocker(); })); t.Start(); } } private string GetMask(DevServer server) { var res = SshHelper.ExcuteCmd(server, "sudo ip route"); if (res.Success) { List lst = new List(); res.Result .Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).Where(o => o.StartsWith("172.")) .ToList() .ForEach(s => { lst.Add(Convert.ToInt32(s.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries)[2])); }); while (true) { var r = new Random().Next(1, 255); if (!lst.Contains(r)) { return r.ToString(); } System.Threading.Thread.Sleep(1); } } else { return new Random().Next(1, 255).ToString(); } } private void tsmi_HospitalRemove_Click(object sender, EventArgs e) { if (!HasSelectdHospital(out DevServer server, out Hospital hospital)) { return; } if (!SftpHelper.Exists(server, $"/home/{server.UserName}/ihdis/compose/{hospital.FileName}")) { MessageBox.Show("医院不存在", "提示"); return; } if (MessageBox.Show("是否确定删除医院?", "提示", MessageBoxButtons.YesNo) == DialogResult.No) { return; } if (SshHelper.InRtmNow()) { MessageBox.Show("正在执行其他命令,请等待!", "提示"); return; } Thread t = new Thread(new ThreadStart(delegate { SshHelper.ExcuteCmdRtm(server, $"cd /home/{server.UserName}/ihdis;sudo bash remove-hospital.sh {hospital.FileName};"); RefreshDocker(); })); t.Start(); } private void tsmi_RemoveLocker_Click(object sender, EventArgs e) { if (!HasSelectdServer(out DevServer server)) return; Utility.RemoveDevFiles(server); } private void tsmi_Stop_Click(object sender, EventArgs e) { if (!HasSelectdHospital(out DevServer server, out Hospital hospital)) { return; } SetStatus("停止docker-compose..."); SshHelper.ExcuteCmd(server, DockerCommand.DockerComposeDown(server.UserName, hospital.FileName, SelectCmdSuffix)); RefreshDocker(treeView_Main.SelectedNode); SetStatus("执行完毕..."); } private void tsmi_Start_Click(object sender, EventArgs e) { if (!HasSelectdHospital(out DevServer server, out Hospital hospital)) { return; } SetStatus("启动docker-compose..."); SshHelper.ExcuteCmd(server, DockerCommand.DockerComposeUp(server.UserName, hospital.FileName, SelectCmdSuffix)); RefreshDocker(treeView_Main.SelectedNode); SetStatus("执行完毕..."); } private void treeView_Main_DrawNode(object sender, DrawTreeNodeEventArgs e) { if (e.State == TreeNodeStates.Selected)//状态判定 { // 背景色(原本的背景色,蓝色) Color bgColor = Color.FromArgb(0, 120, 215); Brush brush = new SolidBrush(bgColor); e.Graphics.FillRectangle(brush, new Rectangle(e.Node.Bounds.Left, e.Node.Bounds.Top, e.Node.Bounds.Width, e.Node.Bounds.Height));//背景色为蓝色 // 绘制文本为蓝底白字 TextRenderer.DrawText(e.Graphics, e.Node.Text, e.Node.TreeView.Font, new Rectangle(e.Node.Bounds.Left + 1, e.Node.Bounds.Top, e.Node.Bounds.Width, e.Node.Bounds.Height), Color.White); } else { e.DrawDefault = true; } } #endregion #region 开发服务器配置 private void tsmi_DevServer_Click(object sender, EventArgs e) { using (Form_DevServer f = new Form_DevServer()) { f.ShowDialog(); } RefreshTree(); } #endregion #region 发布服务器配置 private void tsmi_PulishServer_Click(object sender, EventArgs e) { using (Form_PublishServer f = new Form_PublishServer()) { f.ShowDialog(); } RefreshTree(); } #endregion #region ListView操作 private void tsmi_OpenCode_Click(object sender, EventArgs e) { if (!HasSelectdHospital(out DevServer server, out Hospital hospital)) { return; } if (string.IsNullOrEmpty(hospital.SCPath)) return; try { System.Diagnostics.Process.Start("explorer.exe", "/select," + hospital.SCPath); } catch { } } private void tsmi_HospitalRestart_Click(object sender, EventArgs e) { if (!HasSelectdHospital(out DevServer server, out Hospital hospital)) { return; } SetStatus("重启docker-compose..."); SshHelper.ExcuteCmd(server, DockerCommand.DockerComposeRestart(server.UserName, hospital.FileName, SelectCmdSuffix)); RefreshDocker(treeView_Main.SelectedNode); SetStatus("执行完毕..."); } private void tsmi_HospitalTester_Click(object sender, EventArgs e) { if (!HasSelectdHospital(out DevServer server, out Hospital hospital)) { return; } System.Diagnostics.Process.Start($"http://{server.Ip}:{hospital.DefaultFort}00"); } private void tsmi_Import_Click(object sender, EventArgs e) { if (!HasSelectdHospital(out DevServer server, out Hospital hospital)) { return; } if (server.Ip == Utility.m_TestServerIp) { return; } if (!SftpHelper.Exists(server, $"/home/{server.UserName}/ihdis/compose/{hospital.FileName}")) { MessageBox.Show("医院不存在", "提示"); return; } if (MessageBox.Show($"是否确定导入数据至[{server.Ip}]-[{hospital.FileName}],该操作将清空现有的IHDIS数据库?", "提示", MessageBoxButtons.YesNo) != DialogResult.Yes) { return; } string fname = string.Empty; using (Form_ImportDb f = new Form_ImportDb()) { f.ShowDialog(); fname = f.m_FileName; if (f.m_DialogResult != DialogResult.OK) return; } Thread t = new Thread(new ThreadStart(delegate { ImportSql(server, hospital, fname); })); t.Start(); } object m_InImportSql = new object(); bool b_InImportSql = false; private void ImportSql(DevServer server, Hospital hospital, string fname) { lock (m_InImportSql) { if (b_InImportSql) { return; } b_InImportSql = true; } string remoteFile = $"/tmp/{Guid.NewGuid():N}.sql"; try { SetProgressBarVisible(true); //step 1 上传文件 Utility.SendLog("开始上传文件"); SftpHelper.UploadFile(server, fname, remoteFile, SetProgressBar); //step 2 解析文件 string db = "ihdis"; int tables = 0; bool b_use = false; using (StreamReader sr = new StreamReader(fname)) { var line = sr.ReadLine(); while (line != null) { if (!b_use && line.Contains("USE `ihdis`;")) { b_use = true; db = "mysql"; } if (line.Trim().StartsWith("CREATE TABLE")) { tables++; } line = sr.ReadLine(); } } //step 3 执行导入 Utility.SendLog($"开始导入sql文件,共有表 {tables}"); SshHelper.ExcuteCmd(server, $"cd /home/{server.UserName}/ihdis/compose/{hospital.FileName};sudo docker-compose exec -T mysql mysql -uroot -hlocalhost -pjlmed#123 -e \"DROP DATABASE IF EXISTS ihdis;\";", true); SshHelper.ExcuteCmd(server, $"cd /home/{server.UserName}/ihdis/compose/{hospital.FileName};sudo docker-compose exec -T mysql mysql -uroot -hlocalhost -pjlmed#123 -e \"CREATE DATABASE IF NOT EXISTS ihdis;\";", true); Thread t = new Thread(new ThreadStart(delegate { QueryTables(server, hospital, tables); })); t.Start(); SshHelper.ExcuteCmd(server, $"cd /home/{server.UserName}/ihdis/compose/{hospital.FileName};sudo docker-compose exec -T mysql mysql -uroot -hlocalhost -pjlmed#123 {db} < {remoteFile}", true); Utility.SendLog("导入sql文件完毕"); SshHelper.ExcuteCmd(server, DockerCommand.DockerComposeContainerRestart(server.UserName, hospital.FileName, "webapi", SelectCmdSuffix)); } catch (Exception ex) { Utility.SendLog($"导入sql失败:{ex}"); } finally { SetProgressBarVisible(false); Utility.SendLog($"删除垃圾文件 {remoteFile}"); SftpHelper.Delete(server, remoteFile); lock (m_InImportSql) { b_InImportSql = false; } } } private void QueryTables(DevServer server, Hospital hospital, int sum) { string last = string.Empty; string sql = $"SELECT TABLE_NAME,TABLE_ROWS FROM information_schema.TABLES WHERE TABLE_SCHEMA='ihdis' order by CREATE_TIME DESC,TABLE_NAME DESC;"; string connStr = $"server = {server.Ip}; port = {hospital.DefaultFort}90; userid = root; password = jlmed#123;database=ihdis;"; while (true) { lock (m_InImportSql) { if (!b_InImportSql) { break; } } try { //查询数据库表 DataTable dt = MySqlHelper.ExecuteDataset(connStr, sql).Tables[0]; SetProgressBar(sum, dt.Rows.Count); string cur = $"{dt.Rows[0]["TABLE_NAME"]} {dt.Rows[0]["TABLE_ROWS"]} ..."; if (last != cur) { Utility.SendLog($"[{dt.Rows.Count}/{sum}] {cur}"); last = cur; } } catch { } System.Threading.Thread.Sleep(2000); } } private void listView_App_MouseDoubleClick(object sender, MouseEventArgs e) { QueryLog(); } private void QueryLog() { try { if (listView_App.SelectedItems.Count <= 0) return; var items = listView_App.SelectedItems[0].SubItems[1].Text.Split('_'); if (items.Length < 2) return; if (!HasSelectdHospital(out DevServer server, out Hospital hospital)) { return; } using (Form_Logger f = new Form_Logger(server, hospital, items[1])) { f.ShowDialog(); } } catch { } } private void tsmi_Log_Click(object sender, EventArgs e) { QueryLog(); } private void tsmi_Restart_Click(object sender, EventArgs e) { if (listView_App.SelectedItems.Count <= 0) return; if (!HasSelectdHospital(out DevServer server, out Hospital hospital)) { return; } SetStatus("重启容器中..."); SshHelper.ExcuteCmd(server, DockerCommand.DockeContainerRestart(listView_App.SelectedItems[0].Text)); RefreshDocker(treeView_Main.SelectedNode); SetStatus("执行完毕..."); } #endregion #region 日志操作 private static List m_LogsTemp = new List(); private void timer_Main_Tick(object sender, EventArgs e) { try { lock (m_Logs) { m_LogsTemp.Clear(); m_Logs.ForEach(log => m_LogsTemp.Add(log)); m_Logs.Clear(); } if (m_LogsTemp.Count > 0) { if (lb_Logger.Items.Count > 2000) lb_Logger.Items.Clear(); m_LogsTemp.ForEach(log => lb_Logger.Items.Add(log)); lb_Logger.TopIndex = lb_Logger.Items.Count - 1; } } catch { } } private static List m_Logs = new List(); private void SendLog(string oprator, string msg) { lock (m_Logs) { if (string.IsNullOrEmpty(oprator)) m_Logs.Add($"{DateTime.Now:HH:mm:ss} {msg}"); else m_Logs.Add($"{DateTime.Now:HH:mm:ss} [{oprator}] {msg}"); } } private void tsmi_Copy_Click(object sender, EventArgs e) { if (lb_Logger.SelectedIndex <= 0) return; try { Clipboard.SetDataObject(lb_Logger.Items[lb_Logger.SelectedIndex].ToString(), true); //MessageBox.Show("已经拷贝至系统剪贴板,请执行CTRL+V粘贴!", "提示"); } catch { //MessageBox.Show(ex.Message); } } private void tsmi_Clear_Click(object sender, EventArgs e) { lb_Logger.Items.Clear(); } private void tsmi_ClearCache_Click(object sender, EventArgs e) { try { Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory) .ToList() .ForEach(f => { if (f.EndsWith(".dat")) File.Delete(f); }); } catch { } } private void tsmi_OpenFile_Click(object sender, EventArgs e) { try { string fname = AppDomain.CurrentDomain.BaseDirectory + "Log\\" + DateTime.Now.ToString("yyyy_MM_dd") + ".txt"; System.Diagnostics.Process.Start("explorer.exe", "/select," + fname); } catch { } } private void lb_Logger_DrawItem(object sender, DrawItemEventArgs e) { e.DrawBackground();//绘制背景 Brush myBrush = Brushes.White; if (e.Index >= 0) { var item = lb_Logger.Items[e.Index].ToString(); if (item.Contains("失败") || item.Contains("异常") || item.Contains("错误") || item.Contains("ERR!") || item.Contains("ERROR") || item.Contains("error") || item.Contains("fatal") || item.Contains("failed")) { if (!item.Contains(" 0 个错误")) myBrush = Brushes.Red; } else if (item.Contains("完成") || item.Contains("success") || item.Contains("complete") || item.Contains("Already up")) { myBrush = Brushes.Green; } e.Graphics.FillRectangle(myBrush, e.Bounds); e.DrawFocusRectangle();//焦点框 //文本 e.Graphics.DrawString(lb_Logger.Items[e.Index].ToString(), e.Font, Brushes.Black, e.Bounds, StringFormat.GenericDefault); } } #endregion #region 状态变更 private void SetStatus(string str) { try { BeginInvoke(new EventHandler(delegate { tssl_Oprate.Text = str; })); } catch { } } #endregion #region 项目发布 bool m_InPublish = false; object m_LockPublish = new object(); bool m_RemoveFile = false; bool m_BuildFisrt = false; DevServer m_SelectServer = null; Hospital m_SelectHospital = null; List m_SelectProjects = new List(); private void btn_Publish_Click(object sender, EventArgs e) { lock (m_LockPublish) { if (m_InPublish) return; } #region 初始化选择 var node = treeView_Main.SelectedNode; if (node is null || node.Tag.ToString() != "hospital") { MessageBox.Show("请选择医院!", "提示"); return; } m_SelectServer = Utility.m_DevServers.Where(o => o.Name == node.Parent?.Name).FirstOrDefault(); m_SelectHospital = m_SelectServer?.Hospitals?.Where(o => o.Name == node.Name).FirstOrDefault(); if (m_SelectServer is null || m_SelectHospital is null) return; if (string.IsNullOrEmpty(m_SelectHospital.SCPath) || string.IsNullOrEmpty(m_SelectHospital.WWWPath)) { var h = Utility.m_DevServers.Where(o => o.Ip == "192.168.8.72").FirstOrDefault()?.Hospitals?.Where(o => o.FileName == "develop")?.FirstOrDefault(); if (h != null) { m_SelectHospital.SCPath = h?.SCPath; m_SelectHospital.WWWPath = h?.WWWPath; Utility.SendLog("检测到未配置代码路径,默认使用72开发环境配置"); } else { MessageBox.Show("请先完善医院信息:前后端目录!", "提示"); return; } } m_SelectProjects.Clear(); bool b_back = false; m_RemoveFile = cb_remove.Checked; m_BuildFisrt = cb_build.Checked; if (cb_hfs.Checked) { b_back = true; m_SelectProjects.Add("hfs"); } if (cb_job.Checked) { b_back = true; m_SelectProjects.Add("job"); } if (cb_iot.Checked) { b_back = true; m_SelectProjects.Add("iot"); } if (cb_ts.Checked) { b_back = true; m_SelectProjects.Add("ts"); } if (cb_rtm.Checked) { b_back = true; m_SelectProjects.Add("rtm"); } if (cb_web.Checked) { m_SelectProjects.Add("web"); } if (cb_pad.Checked) { m_SelectProjects.Add("pad"); } if (cb_webapi.Checked) { b_back = true; m_SelectProjects.Add("webapi"); } if (m_SelectHospital.FileName == "produse" && b_back) { MessageBox.Show("后端代码不允许发布至生产服务器!", "提示"); return; } if (m_SelectProjects.Count <= 0) { return; } else { if (MessageBox.Show($"确定发布以下项目?\r\n{string.Join("\r\n", m_SelectProjects)}\r\n至\r\n{m_SelectServer.Ip}\r\n{m_SelectHospital.FileName}({m_SelectHospital.DefaultFort})", "提示", MessageBoxButtons.YesNo) == DialogResult.No) { return; } } #endregion #region 执行发布 new Thread(new ThreadStart(() => { if (m_SelectHospital.FileName != "produse" && Utility.LockDevFiles(m_SelectServer, $"发布[{m_SelectHospital.FileName}]")) { return; } Publish(); RefreshDocker(node); if (m_SelectHospital.FileName != "produse") { Utility.RemoveDevFiles(m_SelectServer); } })).Start(); #endregion } private bool Publish() { Utility.m_StopPublish = false; lock (m_LockPublish) { if (m_InPublish) return false; else m_InPublish = true; } Utility.SendLog("开始执行发布", true); if (m_BuildFisrt && Utility.m_OprateLog.PackGit) { Utility.SendLog("开始拉取最新代码"); if (m_SelectProjects.Any(p => p == "webapi") || m_SelectProjects.Any(p => p == "hfs") || m_SelectProjects.Any(p => p == "rtm") || m_SelectProjects.Any(p => p == "job") || m_SelectProjects.Any(p => p == "iot") || m_SelectProjects.Any(p => p == "ts")) { CmdHelper.ExecCmd($"cd {m_SelectHospital.SCPath}\r\n" + $"{m_SelectHospital.SCPath.Split(':')[0].Trim()}:\r\n" + $"git pull\r\n" + $"exit\r\n"); } else { CmdHelper.ExecCmd($"cd {m_SelectHospital.WWWPath}\r\n" + $"{m_SelectHospital.WWWPath.Split(':')[0].Trim()}:\r\n" + $"git pull\r\n" + $"exit\r\n"); } Utility.SendLog("拉取最新代码完成"); } bool b_suc = true; try { Utility.SetProgressBarVisible(true); int index = 0; Utility.SetProgressBarValue(m_SelectProjects.Count, (ulong)index); m_SelectProjects.ForEach(project => { if (Utility.m_StopPublish) return; if (!b_suc) { return; } try { Utility.SendLog($"{project}", $"开始发布"); ++index; #region 是否执行编译 b_suc = ProjectBuild(project); if (!b_suc) { return; } else { if (project == "web") { //文件不存在,并且目录也不存在,标识未编译 if (!Directory.Exists($"{m_SelectHospital.WWWPath}\\dist")) { Directory.CreateDirectory($"{m_SelectHospital.WWWPath}\\dist"); Utility.SendLog($"{project}", "检测到文件目录dist不存在,已自动创建,继续执行"); } } else if (project == "pad") { //文件不存在,并且目录也不存在,标识未编译 if (!Directory.Exists($"{m_SelectHospital.WWWPath}\\pad-h5\\dist")) { Directory.CreateDirectory($"{m_SelectHospital.WWWPath}\\dist"); Utility.SendLog($"{project}", "检测到文件目录dist不存在,已自动创建,继续执行"); } } } #endregion #region 是否删除远程文件 ProjectRemove(project); #endregion #region 上传文件 b_suc = ProjectUpload(project); if (!b_suc) { return; } #endregion #region 执行pulish行指令 ProjectPublish(project); #endregion Utility.SetProgressBarValue(m_SelectProjects.Count, (ulong)index); Utility.SendLog($"{project}", $"发布 {project} 完毕"); } catch (Exception ex) { Utility.SendLog($"{project}", $"执行发布失败:{ex}"); } }); if (b_suc) { //重启容器(只发布web、pad不需要重启) if (m_SelectProjects.Any(p => p == "webapi") || m_SelectProjects.Any(p => p == "hfs") || m_SelectProjects.Any(p => p == "rtm") || m_SelectProjects.Any(p => p == "job") || m_SelectProjects.Any(p => p == "iot") || m_SelectProjects.Any(p => p == "ts")) { m_SelectProjects.Where(p => p != "web" && p != "pad").ToList().ForEach(p => { Utility.SendLog($"正在重新启动容器 {p}", true); SshHelper.ExcuteCmd(m_SelectServer, DockerCommand.DockerComposeRemove(SelectEnv == "dev" ? m_SelectServer.UserName : SelectEnv, m_SelectHospital.FileName, p, SelectCmdSuffix)); //SshHelper.ExcuteCmd(m_SelectServer, DockerCommand.DockerComposeRemove(m_SelectServer.UserName, m_SelectHospital.FileName, p)); }); SshHelper.ExcuteCmd(m_SelectServer, DockerCommand.DockerComposeUp(SelectEnv == "dev" ? m_SelectServer.UserName : SelectEnv, m_SelectHospital.FileName, SelectCmdSuffix)); //SshHelper.ExcuteCmd(m_SelectServer, DockerCommand.DockerComposeUp(m_SelectServer.UserName, m_SelectHospital.FileName)); } } else { Utility.SendLog($"发布", $"发生错误,执行发布失败,停止发布..."); } } catch (Exception ex) { Utility.SendLog($"执行发布失败:{ex}"); b_suc = false; } finally { Utility.SetProgressBarVisible(false); lock (m_LockPublish) { m_InPublish = false; } } Utility.SendLog("执行发布完毕", true); return b_suc; } /// /// 编译 /// /// private bool ProjectBuild(string project) { if (Utility.m_StopPublish) return false; if (!m_BuildFisrt) return true; Utility.SendLog("编译生成", $"[{project}]开始编译生成"); string cmd; switch (project) { case "webapi": { cmd = $"cd {m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.HttpApi.Hosting\\\r\n{m_SelectHospital.SCPath.Split(':')[0].Trim()}:\r\ndotnet build\r\ndotnet publish -c Release -r linux-x64 --self-contained false -o .\\bin\\Release\\net5.0\\publish\r\nexit\r\n"; break; } case "hfs": { cmd = $"cd {m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.HFS\\\r\n{m_SelectHospital.SCPath.Split(':')[0].Trim()}:\r\ndotnet build\r\ndotnet publish -r linux-x64 --self-contained false -o .\\bin\\Release\\net5.0\\publish\r\nexit\r\n"; break; } case "rtm": { cmd = $"cd {m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.SignalR\\\r\n{m_SelectHospital.SCPath.Split(':')[0].Trim()}:\r\ndotnet build\r\ndotnet publish -r linux-x64 --self-contained false -o .\\bin\\Release\\net5.0\\publish\r\nexit\r\n"; break; } case "job": { cmd = $"cd {m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.BackgroundJobs\\\r\n{m_SelectHospital.SCPath.Split(':')[0].Trim()}:\r\ndotnet build\r\ndotnet publish -r linux-x64 --self-contained false -o .\\bin\\Release\\net5.0\\publish\r\nexit\r\n"; break; } case "iot": { cmd = $"cd {m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.IoT\\\r\n{m_SelectHospital.SCPath.Split(':')[0].Trim()}:\r\ndotnet build\r\ndotnet publish -r linux-x64 --self-contained false -o .\\bin\\Release\\net5.0\\publish\r\nexit\r\n"; break; } case "ts": { var tspath = $"{m_SelectHospital.SCPath.Substring(0, m_SelectHospital.SCPath.LastIndexOf('\\'))}\\adapter\\JianLian.Adapter.Center\\Host\\JianLian.Adapter.Hosting"; cmd = $"cd {tspath}\\\r\n{tspath.Split(':')[0].Trim()}:\r\ndotnet build\r\ndotnet publish -r linux-x64 --self-contained false -o .\\bin\\Release\\net5.0\\publish\r\nexit\r\n"; break; } case "pad": { cmd = $"cd {m_SelectHospital.WWWPath}\\pad-h5\\\r\n{m_SelectHospital.WWWPath.Split(':')[0].Trim()}:\r\nnpm install\r\nnpm run build\r\nexit\r\n"; break; } case "web": { var path = $"cd {m_SelectHospital.WWWPath}\\\r\n{m_SelectHospital.WWWPath.Split(':')[0].Trim()}:\r\n"; cmd = $"{path}npm install -g cnpm --registry=https://registry.npm.taobao.org \r\n cnpm i \r\n npm run build\r\nexit\r\n"; break; } default: return false; } var cmdResult = CmdHelper.ExecCmd(cmd); if (cmdResult.Item1) { Utility.SendLog("编译生成", $"[{project}]编译生成发生错误,终止执行"); Utility.SendLog("编译生成", $"[{project}] {cmdResult.Item2}"); return false; } else { Utility.SendLog("编译生成", $"[{project}]编译生成完毕"); //等待IO操作 System.Threading.Thread.Sleep(2000); return true; } } /// /// 删除远程文件 /// /// private void ProjectRemove(string project) { if (Utility.m_StopPublish) return; if (!m_RemoveFile) return; if (project != "web" && project != "pad") { //SshHelper.ExcuteCmd(m_SelectServer, $"sudo rm -rf /home/{m_SelectServer.UserName}/ihdis/dev/app/server/{project}/*", true); if (SelectEnv == "dev") { SshHelper.ExcuteCmd(m_SelectServer, $"sudo rm -rf /home/{m_SelectServer.UserName}/ihdis/dev/app/server/{project}/*", true); } else { SshHelper.ExcuteCmd(m_SelectServer, $"sudo rm -rf /home/{SelectEnv}/ihdis/{project}/code/*", true); } } else { if (SelectEnv == "dev") { SshHelper.ExcuteCmd(m_SelectServer, $"sudo rm -rf /home/{m_SelectServer.UserName}/ihdis/{(m_SelectHospital.FileName == "produse" ? "produse" : $"compose/{m_SelectHospital.FileName}")}/app/www/{project}/*", true); } else { SshHelper.ExcuteCmd(m_SelectServer, $"sudo rm -rf /home/{SelectEnv}/ihdis/{m_SelectHospital.FileName}/app/www/{project}/*", true); } } } /// /// 上传文件 /// /// private bool ProjectUpload(string project) { if (Utility.m_StopPublish) return false; bool b_suc = true; SetProgressBarVisible(true); try { Utility.SendLog("文件上传", $"[{project}]开始上传文件"); List files = new List(); var toRemotePath = SelectEnv == "dev" ? $"/home/{m_SelectServer.UserName}/ihdis/dev/app/server/{project}" : $"/home/{SelectEnv}/ihdis/{m_SelectHospital.FileName}/code/{project}"; switch (project) { case "webapi": { //更新日志 string llogpath = $"{m_SelectHospital.SCPath}\\src\\Document\\Upgrade.md"; //string rlogpath = $"/home/{m_SelectServer.UserName}/ihdis/compose/{m_SelectHospital.FileName}/data/hfs/wwwroot/files/upgradelogs.md"; var rlogpath = string.Empty; rlogpath = SelectEnv == "dev" ? $"/home/{m_SelectServer.UserName}/ihdis/compose/{m_SelectHospital.FileName}/data/hfs/wwwroot/files/upgradelogs.md" : $"/home/{SelectEnv}/ihdis/{m_SelectHospital.FileName}/data/hfs/wwwroot/files/upgradelogs.md"; if (File.Exists(llogpath)) { SftpHelper.UploadFile(m_SelectServer, llogpath, rlogpath); } //xml文件 string[] fs = Directory.GetFiles($"{m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.HttpApi.Hosting\\bin\\Debug\\net5.0", "*.xml"); fs.ToList().ForEach(fname => { FileInfo file = new FileInfo(fname); files.Add(file.Name); }); SftpHelper.UploadFile(m_SelectServer, $"{m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.HttpApi.Hosting\\bin\\Debug\\net5.0", toRemotePath, files, SetProgressBar); //发布文件 files.Clear(); GetUploadFiles($"{m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.HttpApi.Hosting\\bin\\Release\\net5.0\\publish", $"{m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.HttpApi.Hosting\\bin\\Release\\net5.0\\publish", files); SftpHelper.UploadFile(m_SelectServer, $"{m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.HttpApi.Hosting\\bin\\Release\\net5.0\\publish", toRemotePath, files, SetProgressBar); break; } case "hfs": { //xml文件 string[] fs = Directory.GetFiles($"{m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.HFS\\bin\\Debug\\net5.0", "*.xml"); fs.ToList().ForEach(fname => { FileInfo file = new FileInfo(fname); files.Add(file.Name); }); SftpHelper.UploadFile(m_SelectServer, $"{m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.HFS\\bin\\Debug\\net5.0", toRemotePath, files, SetProgressBar); //发布文件 files.Clear(); GetUploadFiles($"{m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.HFS\\bin\\Release\\net5.0\\publish", $"{m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.HFS\\bin\\Release\\net5.0\\publish", files); SftpHelper.UploadFile(m_SelectServer, $"{m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.HFS\\bin\\Release\\net5.0\\publish", toRemotePath, files, SetProgressBar); break; } case "rtm": { //xml文件 string[] fs = Directory.GetFiles($"{m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.SignalR\\bin\\Debug\\net5.0", "*.xml"); fs.ToList().ForEach(fname => { FileInfo file = new FileInfo(fname); files.Add(file.Name); }); SftpHelper.UploadFile(m_SelectServer, $"{m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.SignalR\\bin\\Debug\\net5.0", toRemotePath, files, SetProgressBar); //发布文件 files.Clear(); GetUploadFiles($"{m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.SignalR\\bin\\Release\\net5.0\\publish", $"{m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.SignalR\\bin\\Release\\net5.0\\publish", files); SftpHelper.UploadFile(m_SelectServer, $"{m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.SignalR\\bin\\Release\\net5.0\\publish", toRemotePath, files, SetProgressBar); break; } case "job": { //xml文件 string[] fs = Directory.GetFiles($"{m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.BackgroundJobs\\bin\\Debug\\net5.0", "*.xml"); fs.ToList().ForEach(fname => { FileInfo file = new FileInfo(fname); files.Add(file.Name); }); SftpHelper.UploadFile(m_SelectServer, $"{m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.BackgroundJobs\\bin\\Debug\\net5.0", toRemotePath, files, SetProgressBar); //发布文件 files.Clear(); GetUploadFiles($"{m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.BackgroundJobs\\bin\\Release\\net5.0\\publish", $"{m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.BackgroundJobs\\bin\\Release\\net5.0\\publish", files); SftpHelper.UploadFile(m_SelectServer, $"{m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.BackgroundJobs\\bin\\Release\\net5.0\\publish", toRemotePath, files, SetProgressBar); break; } case "iot": { //xml文件 string[] fs = Directory.GetFiles($"{m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.IoT\\bin\\Debug\\net5.0", "*.xml"); fs.ToList().ForEach(fname => { FileInfo file = new FileInfo(fname); files.Add(file.Name); }); SftpHelper.UploadFile(m_SelectServer, $"{m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.IoT\\bin\\Debug\\net5.0", toRemotePath, files, SetProgressBar); //发布文件 files.Clear(); GetUploadFiles($"{m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.IoT\\bin\\Release\\net5.0\\publish", $"{m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.IoT\\bin\\Release\\net5.0\\publish", files); SftpHelper.UploadFile(m_SelectServer, $"{m_SelectHospital.SCPath}\\src\\Host\\JianLian.HDIS.IoT\\bin\\Release\\net5.0\\publish", toRemotePath, files, SetProgressBar); break; } case "ts": { var tspath = $"{m_SelectHospital.SCPath.Substring(0, m_SelectHospital.SCPath.LastIndexOf('\\'))}\\adapter\\JianLian.Adapter.Center\\Host\\JianLian.Adapter.Hosting"; //xml文件 string[] fs = Directory.GetFiles($"{tspath}\\bin\\Debug\\net5.0", "*.xml"); fs.ToList().ForEach(fname => { FileInfo file = new FileInfo(fname); files.Add(file.Name); }); SftpHelper.UploadFile(m_SelectServer, $"{tspath}\\bin\\Debug\\net5.0", toRemotePath, files, SetProgressBar); //发布文件 files.Clear(); GetUploadFiles($"{tspath}\\bin\\Release\\net5.0\\publish", $"{tspath}\\bin\\Release\\net5.0\\publish", files); SftpHelper.UploadFile(m_SelectServer, $"{tspath}\\bin\\Release\\net5.0\\publish", toRemotePath, files, SetProgressBar); break; } case "pad": { var fname = $"{AppDomain.CurrentDomain.BaseDirectory}\\dist.zip"; //var rname = $"/home/{m_SelectServer.UserName}/ihdis/{(m_SelectHospital.FileName == "produse" ? "produse" : $"compose/{m_SelectHospital.FileName}")}/app/www/{project}/dist.zip"; var rname = SelectEnv == "dev" ? $"/home/{m_SelectServer.UserName}/ihdis/{(m_SelectHospital.FileName == "produse" ? "produse" : $"compose/{m_SelectHospital.FileName}")}/app/www/{project}/dist.zip" : $"/home/{SelectEnv}/ihdis/{m_SelectHospital.FileName}/app/www/{project}/dist.zip"; //文件不存在,并且目录也不存在,标识未编译 if (!Directory.Exists($"{m_SelectHospital.WWWPath}\\pad-h5\\dist")) { Utility.SendLog($"{project}", "项目未编译,发布失败"); return false; } //执行压缩 Utility.SendLog($"{project}", "正在执行压缩"); ZipHelper.ZipFiles(fname, $"{m_SelectHospital.WWWPath}\\pad-h5\\dist"); files.Add(fname); SftpHelper.UploadFile(m_SelectServer, fname, rname, SetProgressBar); break; } case "web": { var fname = $"{AppDomain.CurrentDomain.BaseDirectory}\\dist.zip"; //var rname = $"/home/{m_SelectServer.UserName}/ihdis/{(m_SelectHospital.FileName == "produse" ? "produse" : $"compose/{m_SelectHospital.FileName}")}/app/www/{project}/dist.zip"; var rname = SelectEnv == "dev" ? $"/home/{m_SelectServer.UserName}/ihdis/{(m_SelectHospital.FileName == "produse" ? "produse" : $"compose/{m_SelectHospital.FileName}")}/app/www/{project}/dist.zip" : $"/home/{SelectEnv}/ihdis/{m_SelectHospital.FileName}/app/www/{project}/dist.zip"; //文件不存在,并且目录也不存在,标识未编译 if (!Directory.Exists($"{m_SelectHospital.WWWPath}\\dist")) { Utility.SendLog($"{project}", "项目未编译,发布失败"); return false; } //执行压缩 Utility.SendLog($"{project}", "正在执行压缩"); ZipHelper.ZipFiles(fname, $"{m_SelectHospital.WWWPath}\\dist"); files.Add(fname); SftpHelper.UploadFile(m_SelectServer, fname, rname, SetProgressBar); break; } default: return false; } } catch (Exception ex) { b_suc = false; throw new Exception(ex.Message); } finally { SetProgressBarVisible(false); } Utility.SendLog("文件上传", $"[{project}]上传文件完毕"); return b_suc; } private void SetProgressBarVisible(bool visible) { try { BeginInvoke(new EventHandler(delegate { tssl_Split2.Visible = visible; tspb_Upload.Visible = visible; tssl_Upload.Visible = visible; })); } catch { } } private void SetProgressBar(long max, ulong value) { SetProgressBar((int)max, (int)value); } private void SetProgressBar(int max, int value) { try { BeginInvoke(new EventHandler(delegate { tspb_Upload.Minimum = 0; tspb_Upload.Maximum = max; tspb_Upload.Value = value; tssl_Upload.Text = $"{value}/{max}"; })); } catch { } } private void GetUploadFiles(string basePath, string path, List files) { string[] fs = Directory.GetFiles(path); fs.ToList().ForEach(fname => { FileInfo file = new FileInfo(fname); files.Add(fname.Replace(basePath + "\\", "")); }); string[] ds = Directory.GetDirectories(path); ds.ToList().ForEach(spath => { if (!spath.EndsWith("Logs")) GetUploadFiles(basePath, spath, files); }); } /// /// 执行指令 /// /// private void ProjectPublish(string project) { if (Utility.m_StopPublish) return; if (project != "web" && project != "pad") { //SshHelper.ExcuteCmd(m_SelectServer, $"sudo rm -rf /home/{m_SelectServer.UserName}/ihdis/compose/{m_SelectHospital.FileName}/data/{project}/*;sudo cp -r /home/{m_SelectServer.UserName}/ihdis/dev/app/server/{project}/* /home/{m_SelectServer.UserName}/ihdis/compose/{m_SelectHospital.FileName}/code/{project}"); //SshHelper.ExcuteCmdRtm(m_SelectServer, $"cd /home/{m_SelectServer.UserName}/ihdis/dev;sudo bash publish-{project}.sh {m_SelectHospital.FileName};"); //SshHelper.ExcuteCmdRtm(m_SelectServer, $"cd /home/{m_SelectServer.UserName}/ihdis/dev;sudo bash publish-copycode.sh {m_SelectHospital.FileName} {project};"); if (SelectEnv == "dev") { SshHelper.ExcuteCmdRtm(m_SelectServer, $"cd /home/{m_SelectServer.UserName}/ihdis/dev;sudo bash publish-copycode.sh {m_SelectHospital.FileName} {project};"); } else { //发布测试环境代码直接发到指定目录了,不需要copy } } else { if (SelectEnv == "dev") { if (m_SelectHospital.FileName == "produse") { SshHelper.ExcuteCmdRtm(m_SelectServer, $"unzip -o -d /home/{m_SelectServer.UserName}/ihdis/produse/app/www/{project} /home/{m_SelectServer.UserName}/ihdis/produse/app/www/{project}/dist.zip"); } else { SshHelper.ExcuteCmdRtm(m_SelectServer, $"cd /home/{m_SelectServer.UserName}/ihdis;sudo bash unzip-www.sh {m_SelectHospital.FileName} {project};"); } } else { SshHelper.ExcuteCmdRtm(m_SelectServer, $"unzip -o -d /home/{SelectEnv}/ihdis/{m_SelectHospital.FileName}/app/www/{project} /home/{SelectEnv}/ihdis/{m_SelectHospital.FileName}/app/www/{project}/dist.zip"); } } } private void btn_Stop_Click(object sender, EventArgs e) { Utility.m_StopPublish = true; } #endregion #region 项目打包 bool b_InPublishNew = false; private void tsmi_Pack_Click(object sender, EventArgs e) { var node = treeView_Main.SelectedNode; var server = Utility.m_DevServers.Where(o => o.Name == node?.Parent?.Name).FirstOrDefault(); var hospital = server?.Hospitals?.Where(o => o.Name == node?.Name).FirstOrDefault(); if (b_InPublishNew) { return; } b_InPublishNew = true; try { #region 初始化 using (Form_Publish f = new Form_Publish(server, hospital)) { f.ShowDialog(); if (f.m_DialogResult != DialogResult.Yes) { return; } } string version = Utility.m_OprateLog.PackVersion; DevServer devServer = Utility.m_DevServers.Where(o => o.Ip == Utility.m_OprateLog.PackDevIp).FirstOrDefault(); hospital = devServer?.Hospitals.Where(o => o.FileName == Utility.m_OprateLog.PackHospital).FirstOrDefault(); PublishServer publishServer = Utility.m_PublishServers.Where(o => o.Ip == Utility.m_OprateLog.PackPublishIp).FirstOrDefault(); if (devServer is null) { Utility.SendLog("打包", $"开发服务器不存在 {devServer.Ip}"); return; } if (hospital is null) { Utility.SendLog("打包", $"医院不存在 {hospital.FileName}"); return; } if (publishServer is null) { Utility.SendLog("打包", $"发布服务器不存在 {publishServer.Ip}"); return; } if (string.IsNullOrEmpty(hospital.SCPath) || string.IsNullOrEmpty(hospital.WWWPath)) { var h = Utility.m_DevServers.Where(o => o.Ip == "192.168.8.72").FirstOrDefault()?.Hospitals?.Where(o => o.FileName == "develop")?.FirstOrDefault(); if (h != null) { hospital.SCPath = h?.SCPath; hospital.WWWPath = h?.WWWPath; Utility.SendLog("检测到未配置代码路径,默认使用72开发环境配置"); } else { MessageBox.Show("请先完善医院信息:前后端目录!", "提示"); return; } } server = devServer; #endregion #region 是否先执行发布、或者是升级包 m_SelectServer = devServer; m_SelectHospital = hospital; if (m_SelectServer is null || m_SelectHospital is null) return; m_SelectProjects.Clear(); m_RemoveFile = cb_remove.Checked; m_BuildFisrt = cb_build.Checked; if (cb_hfs.Checked) { m_SelectProjects.Add("hfs"); } if (cb_job.Checked) { m_SelectProjects.Add("job"); } if (cb_rtm.Checked) { m_SelectProjects.Add("rtm"); } if (cb_iot.Checked) { m_SelectProjects.Add("iot"); } if (cb_ts.Checked) { m_SelectProjects.Add("ts"); } if (cb_web.Checked) { if (!Directory.Exists($"{m_SelectHospital.WWWPath}\\node_modules")) { MessageBox.Show("Web项目未执行npm install,直接发布将会报错!"); return; } m_SelectProjects.Add("web"); } if (cb_pad.Checked) { if (!Directory.Exists($"{m_SelectHospital.WWWPath}\\pad-h5\\node_modules")) { MessageBox.Show("Pad项目未执行npm install,直接发布将会报错!"); return; } m_SelectProjects.Add("pad"); } if (cb_webapi.Checked) { m_SelectProjects.Add("webapi"); } if (Utility.m_OprateLog.PackUpgrade) { if (!m_SelectProjects.Any() && !cb_andriod.Checked) { MessageBox.Show("升级包未选择任何模块,不再执行!"); return; } } #endregion #region 指令生成 List cmdlist = new List(); //生成基础包文件 cmdlist.Add($"sudo rm -rf /home/{publishServer.UserName}/ihdis/packages/{hospital.FileName}/{version}"); cmdlist.Add($"sudo mkdir -p /home/{publishServer.UserName}/ihdis/packages/{hospital.FileName}/{version}"); cmdlist.Add($"sudo cp -r /home/{publishServer.UserName}/ihdis/packages/sample/* /home/{publishServer.UserName}/ihdis/packages/{hospital.FileName}/{version}"); #region 安装包需要打包镜像 if (!Utility.m_OprateLog.PackUpgrade) { //镜像版本文件的环境变量 string env = $"\"IHDIS_PORT=600\n" + $"mask=60\n" + $"redis_TAG=5.0.5\n" + $"mysql_TAG=8.0\n" + $"nginx_TAG=1.17\n" + $"rabbitmq_TAG=3.7.17-management\n" + $"adminer_TAG=4.7.1\n" + $"phpredisadmin_TAG=v1.11.4\n" + $"portainer_TAG=1.22.0\n" + $"webapi_TAG={version}\n" + $"hfs_TAG={version}\n" + $"rtm_TAG={version}\n" + $"iot_TAG={version}\n" + $"ts_TAG={version}\n" + $"job_TAG={version}\""; cmdlist.Add($"sudo echo -e {env} > /home/{publishServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/.env"); //APP镜像生成 SetAppCmd(hospital, devServer, version, cmdlist, cb_webapi); SetAppCmd(hospital, devServer, version, cmdlist, cb_hfs); SetAppCmd(hospital, devServer, version, cmdlist, cb_rtm); SetAppCmd(hospital, devServer, version, cmdlist, cb_job); SetAppCmd(hospital, devServer, version, cmdlist, cb_iot); SetAppCmd(hospital, devServer, version, cmdlist, cb_ts); } #endregion bool b_ts = Utility.m_OprateLog.PackUpgrade && Utility.m_OprateLog.PackUpgradeTS; #region TS插件包 if (b_ts) { //ts升级包,只拷贝ts文件 cmdlist.Add($"sudo cp -r /home/{devServer.UserName}/ihdis/dev/app/server/ts /home/{devServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/code"); } #endregion #region 安装包/升级包 else { //后端代码映射 cmdlist.Add($"sudo cp -r /home/{devServer.UserName}/ihdis/dev/app/server/* /home/{devServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/code"); //升级包移除ts文件 if (Utility.m_OprateLog.PackUpgrade) cmdlist.Add($"sudo rm -rf /home/{devServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/code/ts/*"); //版本升级日志 cmdlist.Add($"sudo cp /home/{devServer.UserName}/ihdis/compose/{hospital.FileName}/data/hfs/wwwroot/files/upgradelogs.md /home/{publishServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/data/hfs/wwwroot/files/upgradelogs.md"); cmdlist.Add($"sudo echo {version} > /home/{devServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/Version"); //PC代码 var cname = cb_web.Text; cmdlist.Add($"sudo rm -rf /home/{devServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/app/www/{cname}/*"); cmdlist.Add($"sudo rm -rf /home/{devServer.UserName}/ihdis/compose/{hospital.FileName}/app/www/{cname}/dist.zip"); cmdlist.Add($"sudo cp -r /home/{devServer.UserName}/ihdis/compose/{hospital.FileName}/app/www/{cname} /home/{publishServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/app/www/"); //PAD-H5代码:只有是升级包并且未勾选,才会不打包该模块 cname = cb_pad.Text; cmdlist.Add($"sudo rm -rf /home/{devServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/app/www/{cname}/*"); cmdlist.Add($"sudo rm -rf /home/{devServer.UserName}/ihdis/compose/{hospital.FileName}/app/www/{cname}/dist.zip"); cmdlist.Add($"sudo cp -r /home/{devServer.UserName}/ihdis/compose/{hospital.FileName}/app/www/{cname} /home/{publishServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/app/www/"); //PAD-Andriod文件 var cmdStr = CopyPadCmd(devServer, hospital, publishServer, version, $"hdis"); if (!string.IsNullOrWhiteSpace(cmdStr)) cmdlist.Add(cmdStr); //基础数据库文件(包含TS):安装包、升级包必有 cmdlist.Add($"sudo cp /home/{devServer.UserName}/ihdis/packages/tempdb/{hospital.FileName}/{version}/hdis_table.sql /home/{publishServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/conf/mysql/"); cmdlist.Add($"sudo echo {version} > /home/{devServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/Version"); } if (Utility.m_OprateLog.PackUpgrade) { //升级包删除多余的文件 cmdlist.Add($"sudo rm -rf /home/{devServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/conf/*"); cmdlist.Add($"sudo rm -rf /home/{devServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/data/iot"); cmdlist.Add($"sudo rm -rf /home/{devServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/data/mysql"); cmdlist.Add($"sudo rm -rf /home/{devServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/data/oracle"); cmdlist.Add($"sudo rm -rf /home/{devServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/data/portainer"); cmdlist.Add($"sudo rm -rf /home/{devServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/data/rabbitmq"); cmdlist.Add($"sudo rm -rf /home/{devServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/data/redis"); cmdlist.Add($"sudo rm -rf /home/{devServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/data/ts"); cmdlist.Add($"sudo rm -rf /home/{devServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/data/webapi"); cmdlist.Add($"sudo rm -rf /home/{devServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/install/*"); cmdlist.Add($"sudo rm -rf /home/{devServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/log/*"); cmdlist.Add($"sudo rm -rf /home/{devServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/load_images.cmd"); cmdlist.Add($"sudo rm -rf /home/{devServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/load_images.sh"); cmdlist.Add($"sudo rm -rf /home/{devServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/docker-compose.yml"); } #endregion //包注释文件 cmdlist.Add($"sudo cp /tmp/v{version}_log.dat /home/{devServer.UserName}/ihdis/packages/versions/{hospital.FileName}/v{version}_log.dat"); //压缩文件 cmdlist.Add($"sudo mkdir /home/{devServer.UserName}/ihdis/packages/versions/{hospital.FileName}/"); cmdlist.Add($"sudo rm -rf /home/{devServer.UserName}/ihdis/packages/versions/{hospital.FileName}/{version}.zip"); cmdlist.Add($"cd /home/{devServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/ && sudo zip /home/{devServer.UserName}/ihdis/packages/versions/{hospital.FileName}/{version}.zip -r ./"); cmdlist.Add($"sudo chmod 777 /home/{devServer.UserName}/ihdis/packages/versions/version_list"); cmdlist.Add($"sudo echo {version} >> /home/{devServer.UserName}/ihdis/packages/versions/version_list"); //清理缓存文件 cmdlist.Add($"sudo rm -rf /home/{publishServer.UserName}/ihdis/packages/{hospital.FileName}/{version}"); cmdlist.Add($"sudo rm -rf /home/{devServer.UserName}/ihdis/packages/tempdb/{hospital.FileName}/*"); #endregion #region 开始执行脚本 Thread t = new Thread(new ThreadStart(delegate { var flag = Utility.m_OprateLog.PackUpgrade ? (Utility.m_OprateLog.PackUpgradeTS ? "[TS插件包]" : "[升级包]") : "[基础包]"; if (Utility.LockDevFiles(server, $"{flag}打包[{hospital.FileName}]")) { return; } try { Utility.SetStatus($"{flag}开始打包"); #region TS打包 if (Utility.m_OprateLog.PackUpgrade && Utility.m_OprateLog.PackUpgradeTS) { //ts升级包,单独处理 var tspath = AppDomain.CurrentDomain.BaseDirectory.Replace(@"assistant\JianLian.Assistant\JianLian.HDIS.PublishHelper\bin\Debug\", "") + @"adapter\JianLian.Adapter.Center"; Utility.SendLog(flag, $"编译项目"); CmdHelper.ExecCmd($"cd {tspath}\\Host\\JianLian.Adapter.Hosting\r\n" + $"{tspath.Split(':')[0].Trim()}:\r\n" + $"dotnet publish -r linux-x64 --self-contained false -o .\\bin\\Release\\net5.0\\publish\r\n" + $"exit\r\n"); //编译TS组件 Utility.SendLog(flag, $"编译组件 {hospital}"); CmdHelper.ExecCmd($"cd {tspath}\\Custom\\JianLian.Adapter.{Utility.m_OprateLog.PackUpgradeTSCustom}\r\n" + $"{tspath.Split(':')[0].Trim()}:\r\n" + $"dotnet build\r\n" + $"exit\r\n"); //清除文件 SshHelper.ExcuteCmd(devServer, $"rm -rf /home/{m_SelectServer.UserName}/ihdis/dev/app/server/ts/*", true); //上传文件 List files = new List(); string[] fs = Directory.GetFiles($"{tspath}\\Host\\JianLian.Adapter.Hosting\\bin\\Debug\\net5.0", "*.xml"); fs.ToList().ForEach(fname => { FileInfo file = new FileInfo(fname); files.Add(file.Name); }); SftpHelper.UploadFile(m_SelectServer, $"{tspath}\\Host\\JianLian.Adapter.Hosting\\bin\\Debug\\net5.0", $"/home/{m_SelectServer.UserName}/ihdis/dev/app/server/ts", files, SetProgressBar); files.Clear(); GetUploadFiles($"{tspath}\\Host\\JianLian.Adapter.Hosting\\bin\\Release\\net5.0\\publish", $"{tspath}\\Host\\JianLian.Adapter.Hosting\\bin\\Release\\net5.0\\publish", files); SftpHelper.UploadFile(m_SelectServer, $"{tspath}\\Host\\JianLian.Adapter.Hosting\\bin\\Release\\net5.0\\publish", $"/home/{m_SelectServer.UserName}/ihdis/dev/app/server/ts", files, SetProgressBar); files.Clear(); GetUploadFiles($"{tspath}\\Custom\\JianLian.Adapter.{Utility.m_OprateLog.PackUpgradeTSCustom}\\bin\\Debug\\net5.0", $"{tspath}\\Custom\\JianLian.Adapter.{Utility.m_OprateLog.PackUpgradeTSCustom}\\bin\\Debug\\net5.0", files); SftpHelper.UploadFile(m_SelectServer, $"{tspath}\\Custom\\JianLian.Adapter.{Utility.m_OprateLog.PackUpgradeTSCustom}\\bin\\Debug\\net5.0", $"/home/{m_SelectServer.UserName}/ihdis/dev/app/server/ts", files, SetProgressBar); } #endregion #region 安装包/升级包 else { #region 发布 bool b_suc = true; if (Utility.m_OprateLog.PackPublish) { if (m_SelectProjects.Count > 0) { b_suc = Publish(); } } else { Utility.SendLog($"{flag}不需要执行发布流程,默认使用服务端文件"); } if (!b_suc) { Utility.SendLog($"{flag}由于发布失败,打包不继续执行"); return; } #endregion #region 生成数据库脚本文件 var newdb = $"hdis_{version.Replace(".", "_")}"; if (Utility.m_OprateLog.PackDbFile) { Utility.SendLog($"{flag}等待程序初始化 10 秒"); System.Threading.Thread.Sleep(10000); //需要先设置数据库密码为空,再设置回来 //生成最新版本数据库文件 SshHelper.ExcuteCmd(devServer, $"cd /home/{devServer.UserName}/ihdis/compose/{hospital.FileName};sudo docker-compose exec -T mysql mysql -uroot -hlocalhost -e \"ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY ''; flush privileges; \"", true); SshHelper.ExcuteCmd(devServer, $"cd /home/{devServer.UserName}/ihdis/compose/{hospital.FileName};sudo docker-compose exec -T mysql mysql -uroot -hlocalhost -e \"CREATE DATABASE IF NOT EXISTS {newdb};\";", true); SshHelper.ExcuteCmd(devServer, $"cd /home/{devServer.UserName}/ihdis/compose/{hospital.FileName};sudo docker-compose exec -T mysql /bin/bash -c \"mysqldump hdis -uroot | mysql {newdb} -uroot\"", true); //上传reset.sql并执行 string resetsql = File.ReadAllText($"{hospital.SCPath}/src/Document/build/reset.sql", Encoding.UTF8).Replace("use hdis_compare;", $"use {newdb};"); var rsfname = Utility.GetTempFileName("reset.sql"); File.WriteAllText(rsfname, resetsql, Encoding.UTF8); SftpHelper.UploadFile(devServer, rsfname, "/tmp/reset.sql"); SshHelper.ExcuteCmd(devServer, $"cd /home/{devServer.UserName}/ihdis/compose/{hospital.FileName};sudo docker-compose exec -T mysql mysql -uroot -hlocalhost {newdb} < /tmp/reset.sql"); SshHelper.ExcuteCmd(devServer, $"cd /home/{devServer.UserName}/ihdis/compose/{hospital.FileName};sudo docker-compose exec -T mysql mysql -uroot -hlocalhost -e \"ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'jlmed#123'; flush privileges; \"", true); //下载数据库 DownLoadDb(devServer, hospital, newdb); string allPath = $"{hospital.SCPath}\\src\\Document\\script\\hdis.sql"; // 转换编码 string allText = File.ReadAllText(allPath); File.WriteAllText(allPath, allText); } else { Utility.SendLog($"{flag}不需要打包最新数据库,使用本地文件 {hospital.SCPath}\\src\\Document\\script\\hdis.sql"); Utility.SendLog($"{flag}{hospital.SCPath}\\src\\Document\\script\\hdis.sql"); Utility.SendLog($"{flag}{hospital.SCPath}\\src\\Document\\script\\hdis_ts.sql"); } //合并ts数据库 string ihdis_sql = File.ReadAllText($"{hospital.SCPath}\\src\\Document\\script\\hdis.sql"); string ihdis_ts_sql = File.ReadAllText($"{hospital.SCPath}\\src\\Document\\script\\hdis_ts.sql"); string sql = $" use `hdis`; \n {ihdis_sql} \n use `hdis_ts`; \n {ihdis_ts_sql}"; var sql_fname = Utility.GetTempFileName("hdis_table.sql"); File.WriteAllText(sql_fname, $"{sql}"); //上传数据库文件 SftpHelper.CreateDirectory(publishServer, $"/home/{publishServer.UserName}/ihdis/packages/tempdb/{hospital.FileName}/"); SftpHelper.CreateDirectory(publishServer, $"/home/{publishServer.UserName}/ihdis/packages/tempdb/{hospital.FileName}/{version}/"); System.Threading.Thread.Sleep(1000); SftpHelper.UploadFile(publishServer, sql_fname, $"/home/{publishServer.UserName}/ihdis/packages/tempdb/{hospital.FileName}/{version}/hdis_table.sql", null, true); //开始生成数据库脚本 var localFile = Utility.GetTempFileName($"v{Utility.m_OprateLog.PackVersion}_sql.zip"); SftpHelper.CreateDirectory(publishServer, $"/home/{publishServer.UserName}/ihdis/packages/versions/{hospital.FileName}/"); var remoteFile = $"/home/{publishServer.UserName}/ihdis/packages/versions/{hospital.FileName}/v{Utility.m_OprateLog.PackVersion}_sql.zip"; CreateDbFile(localFile, hospital); System.Threading.Thread.Sleep(1000); SftpHelper.UploadFile(publishServer, localFile, remoteFile); #endregion } #endregion #region 包注释文件 StringBuilder sb_comment = new StringBuilder(); sb_comment.AppendLine(Utility.m_OprateLog.PackUpgrade ? "Upgrade Package" : "Installation Package"); sb_comment.AppendLine($"Version: {version}"); sb_comment.AppendLine($"PackageTime: {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}"); sb_comment.AppendLine($"PackageEnvironment: {devServer.Ip} {hospital.FileName}"); sb_comment.AppendLine($"Operator: {Environment.MachineName}"); sb_comment.AppendLine($"Moudule: {((Utility.m_OprateLog.PackUpgrade && Utility.m_OprateLog.PackUpgradeTS) ? "ts" : string.Join($"; ", this.gb_Oprate.Controls.Cast().Where(o => o is CheckBox c && (Utility.m_OprateLog.PackUpgrade ? c.Name != "cb_ts" : true) && c.Name != "cb_remove" && c.Name != "cb_build").Select(o => o.Text).OrderBy(o => o)))}"); string lfname = Utility.GetTempFileName($"v{version}_log.dat"); string rfname = $"/tmp/v{version}_log.dat"; File.WriteAllText(lfname, sb_comment.ToString(), Encoding.UTF8); SftpHelper.UploadFile(server, lfname, rfname); #endregion #region 执行指令 SshHelper.ExcuteCmds(devServer, cmdlist, $"{flag}版本打包"); #endregion if (Utility.m_OprateLog.PackDownload) { var path = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory); Utility.SendLog("下载", "开始执行下载", true); Utility.SetProgressBarVisible(true); SftpHelper.DownloadFile(server, $"/home/{server.UserName}/ihdis/packages/versions/{hospital.FileName}/{version}.zip", $"{path}\\{version}.zip", true, progress: Utility.SetProgressBarValue); SftpHelper.DownloadFile(server, $"/home/{server.UserName}/ihdis/packages/versions/{hospital.FileName}/v{version}_log.dat", $"{path}\\v{version}_log.dat", true, progress: Utility.SetProgressBarValue); SftpHelper.DownloadFile(server, $"/home/{server.UserName}/ihdis/packages/versions/{hospital.FileName}/v{version}_sql.zip", $"{path}\\v{version}_sql.zip", true, progress: Utility.SetProgressBarValue, completedAction: () => { Utility.SendLog("下载", "文件全部下载完毕", true); var cfile = $"{path}\\v{version}_log.dat"; if (File.Exists(cfile)) { Utility.SendLog("下载", "开始添加压缩包版本注释", true); var comment = File.ReadAllText(cfile, Encoding.UTF8); if (!b_ts) { ZipHelper.SetComment($"{path}\\v{version}_sql.zip", comment); } ZipHelper.SetComment($"{path}\\{version}.zip", comment); try { Directory.GetFiles(path, "*zip.*.tmp").ToList().ForEach(f => { File.Delete(f); }); File.Delete(cfile); } catch { } Utility.SendLog("下载", "完成", true); } }); Utility.SetProgressBarVisible(false); } else { Utility.SetStatus($"{flag}打包完毕,请使用本工具下载安装包,否则会现场安装时导致安装包校验不通过。"); } } catch (Exception ex) { Utility.SendLog($"{flag}打包异常:{ex.Message}"); } finally { Utility.RemoveDevFiles(server); } })); t.Start(); #endregion } finally { b_InPublishNew = false; } } private string CopyPadCmd(DevServer devServer, Hospital hospital, PublishServer publishServer, string version, string db) { string sql = $"SELECT Version FROM SystemPadVersion ORDER BY ABS(NOW() - CreationTime) ASC LIMIT 0, 1;"; string connStr = $"server = {devServer.Ip}; port = {hospital.DefaultFort}90; userid = root; password = jlmed#123;database={db};"; DataTable dt = MySqlHelper.ExecuteDataset(connStr, sql).Tables[0]; if (dt.Rows.Count > 0) { return $"sudo cp /home/{devServer.UserName}/ihdis/compose/{hospital.FileName}/data/hfs/wwwroot/files/pad/{dt.Rows[0][0].ToString()}.apk /home/{publishServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/data/hfs/wwwroot/files/pad/{dt.Rows[0][0].ToString()}.apk"; } else { return string.Empty; } } private void DownLoadDb(DevServer devServer, Hospital hospital, string db) { Utility.SetProgressBarVisible(true); //查询数据库表 string sql = $"SELECT * FROM INFORMATION_SCHEMA.`COLUMNS` C WHERE C.TABLE_SCHEMA = '{db}';"; string connStr = $"server = {devServer.Ip}; port = {hospital.DefaultFort}90; userid = root; password = jlmed#123;database={db};"; DataTable dt = MySqlHelper.ExecuteDataset(connStr, sql).Tables[0]; Dictionary> tables = new Dictionary>(); foreach (DataRow dr in dt.Rows) { if (!tables.ContainsKey(dr["TABLE_NAME"].ToString())) { tables.Add(dr["TABLE_NAME"].ToString(), new List { dr["COLUMN_NAME"].ToString() }); } else { tables[dr["TABLE_NAME"].ToString()].Add(dr["COLUMN_NAME"].ToString()); } } //导出数据 try { Utility.SendLog("导出数据库", "共有表 " + tables.Count); string fname = $"{hospital.SCPath}\\src\\Document\\script\\hdis.sql"; if (File.Exists(fname)) { File.Delete(fname); } int tcount = 0; StringBuilder sb = new StringBuilder(); sb.AppendLine("SET FOREIGN_KEY_CHECKS = 0;"); tables.Keys.ToList().ForEach(tabelname => { Utility.SetProgressBarValue(tables.Keys.Count, (ulong)++tcount); sb.AppendLine($"-- 正在导出 表 {db}.{tabelname} 结构"); //Utility.SendLog("导出数据库", $"-- 正在导出 表 ihdis.{tabelname} 结构"); //删除原表 //sb.AppendLine($"DROP TABLE IF EXISTS `{tabelname}`;"); //导出表结构 sb.AppendLine($"{MySqlHelper.ExecuteDataset(connStr, $"SHOW CREATE TABLE `{db}`.`{tabelname}`;").Tables[0].Rows[0]["Create Table"]};"); sb.AppendLine(); //导出数据 sb.AppendLine($"-- 正在导出 表 {db}.{tabelname} 数据"); int rows = int.Parse(MySqlHelper.ExecuteScalar(connStr, $"SELECT COUNT(0) FROM `{db}`.`{tabelname}`;").ToString()); //Utility.SendLog("导出数据库", $"-- 正在导出 表 ihdis.{tabelname} 数据,共有数据 {rows}"); int sum = 0; using (MySqlDataReader reader = MySqlHelper.ExecuteReader(connStr, $"SELECT * FROM `{db}`.`{tabelname}`;")) { if (reader.HasRows) { //字段类型 Dictionary dic = new Dictionary(); //添加字段 //sb.AppendLine($"DELETE FROM `{tabelname}`;"); StringBuilder sb_insert = new StringBuilder(); sb_insert.Append($"INSERT INTO `{tabelname}` ("); for (int i = 0; i < reader.FieldCount; ++i) { sb_insert.Append($"`{reader.GetName(i)}`"); if (i != reader.FieldCount - 1) sb_insert.Append(", "); dic.Add(i, reader.GetDataTypeName(i)); } sb_insert.Append(") VALUES"); sb_insert.AppendLine(); //表开始 WriteToFile(fname, $"{sb}"); sb.Clear(); int index = 0; //添加数据 while (reader.Read()) { sum++; sb.Append("\t("); for (int i = 0; i < reader.FieldCount; ++i) { sb.Append($"{ConvertData(reader[i], dic[i])}"); if (i != reader.FieldCount - 1) sb.Append(", "); } sb.Append(")"); //500行数据入库一次 if (index++ >= 500) { sb.Append(";"); sb.AppendLine(); sb.AppendLine(); WriteToFile(fname, $"{sb_insert}{sb}"); sb.Clear(); index = 0; continue; } //1024KB为一组插入语句 if (sb.Length >= 100 * 1024) { sb.Append(";"); sb.AppendLine(); sb.AppendLine(); WriteToFile(fname, $"{sb_insert}{sb}"); sb.Clear(); index = 0; continue; } if (sum != rows) sb.Append(","); else sb.Append(";"); sb.AppendLine(); } //表结束 if (sb.Length > 0) { sb.AppendLine(); WriteToFile(fname, $"{sb_insert}{sb}"); sb.Clear(); index = 0; } } } sb.AppendLine(); }); sb.AppendLine("SET FOREIGN_KEY_CHECKS = 1;"); if (sb.Length > 0) WriteToFile(fname, sb.ToString()); Utility.SendLog("导出数据库", $"导出数据完毕"); } catch (Exception ex) { Utility.SendLog("导出数据库", "导出数据异常" + ex.ToString()); } Utility.SetProgressBarVisible(false); } private string ConvertData(object data, string type) { if (data.GetType().FullName == "System.DBNull") return "NULL"; string value; if (type.Contains("CHAR")) //varchar ,char { value = data.ToString(); if (value.IndexOf("\r") > 0) value = value.Replace("\r", "\\r"); if (value.IndexOf("\n") > 0) value = value.Replace("\n", "\\n"); if (value.IndexOf("'") > 0) value = value.Replace("'", "''"); if (value.IndexOf("\\") > 0) value = value.Replace("\\", "\\\\"); value = $"'{value}'"; } else if (type.Contains("JSON")) { value = data.ToString().Trim() == "" ? "NULL" : $"'{data}'"; } else if (type.Contains("TIMESTAMP") || type.Contains("DATETIME")) { value = data.ToString().Trim() == "" ? "NULL" : $"'{Convert.ToDateTime(data.ToString()):yyyy-MM-dd HH:mm:ss}'"; } else if (type.Contains("DATE")) { value = data.ToString().Trim() == "" ? "NULL" : $"'{Convert.ToDateTime(data.ToString()):yyyy-MM-dd}'"; } else { value = data.ToString().Trim() == "" ? "NULL" : data.ToString(); } return value; } private void WriteToFile(string fname, string content) { if (!File.Exists(fname)) { using (StreamWriter sw = File.CreateText(fname)) { sw.Write(content); } } else { using (StreamWriter sw = File.AppendText(fname)) { sw.Write(content); } } } /// /// 创建并复镜像文件 /// /// /// /// /// /// private void SetAppCmd(Hospital hospital, DevServer devServer, string version, List cmdlist, CheckBox cb) { var cname = cb.Text; cmdlist.Add($"rm -rf /home/{devServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/app/images/{cname}.*"); cmdlist.Add($"sh /home/{devServer.UserName}/ihdis/dev/build-one.sh {version} {cname} {devServer.UserName} {hospital.FileName}"); cmdlist.Add($"cp /home/{devServer.UserName}/ihdis/dev/app/images/{cname}.{version}.tar.gz /home/{devServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/app/images/"); //cmdlist.Add($"ssh {publishServer.Ip} sh /home/{publishServer.UserName}/ihdis/script/publish.sh {version} {cname}"); //cmdlist.Add($"sudo sed -i \"s/${version}_TAG.*/${version}_TAG=${cname}/\" /home/{devServer.UserName}/ihdis/packages/{version}/.env"); cmdlist.Add($"sudo sed -i \"s/images\\/{cname}\\..*.tar.gz/images\\/{cname}.{version}.tar.gz/\" /home/{devServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/load_images.cmd"); cmdlist.Add($"sudo sed -i \"s/images\\/{cname}\\..*.tar.gz/images\\/{cname}.{version}.tar.gz/\" /home/{devServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/load_images.sh"); cmdlist.Add($"sudo rm -rf /home/{devServer.UserName}/ihdis/dev/app/images/{cname}.{version}*"); cmdlist.Add($"sudo cp -r /home/{devServer.UserName}/ihdis/dev/app/server/ts /home/{devServer.UserName}/ihdis/packages/{hospital.FileName}/{version}/data"); } private bool CreateDbFile(string fname, Hospital hospital) { bool b_suc = false; //创建文件夹 string path = fname.Substring(0, fname.LastIndexOf(".")); DirectoryInfo dir; FileSystemInfo[] fileinfo; if (Directory.Exists(path)) { dir = new DirectoryInfo(path); fileinfo = dir.GetFileSystemInfos(); //返回目录中所有文件和子目录 foreach (FileSystemInfo i in fileinfo) { if (i is DirectoryInfo) //判断是否文件夹 { DirectoryInfo subdir = new DirectoryInfo(i.FullName); subdir.Delete(true); //删除子目录和文件 } else { File.Delete(i.FullName); //删除指定文件 } } Directory.Delete(path); } Directory.CreateDirectory(path); Utility.SendLog("版本打包", $"创建临时目录 {path}"); //比对脚本 \tools\HH.iHDIS.OPS.Tool\HH.iHDIS.OPS.Tool\Config\CompareConfig.json string toolsPath = AppDomain.CurrentDomain.BaseDirectory.Replace("\\JianLian.HDIS.PublishHelper\\bin\\Debug\\", ""); if (File.Exists($"{toolsPath}\\JianLian.HDIS.OPS.Tool\\Config\\CompareConfig.json")) { if (File.Exists($"{path}\\CompareConfig.json")) { File.Delete($"{path}\\CompareConfig.json"); } File.Copy($"{toolsPath}\\JianLian.HDIS.OPS.Tool\\Config\\CompareConfig.json", $"{path}\\CompareConfig.json"); Utility.SendLog("版本打包", $"复制文件 {$"{toolsPath}\\JL.HDIS.OPS.Tool\\Config\\CompareConfig.json"} =>> {path}\\CompareConfig.json"); } else { Utility.SendLog("版本打包", $"未能找到比对脚本:{toolsPath}\\JL.HDIS.OPS.Tool\\Config\\CompareConfig.json"); return b_suc; } //数据库脚本 \sc\script\ihdis.sql if (File.Exists($"{hospital.SCPath}\\src\\Document\\script\\hdis.sql")) { if (File.Exists($"{path}\\hdis.sql")) { File.Delete($"{path}\\hdis.sql"); } File.Copy($"{hospital.SCPath}\\src\\Document\\script\\hdis.sql", $"{path}\\hdis.sql"); Utility.SendLog("版本打包", $"复制文件 {hospital.SCPath}\\src\\Document\\script\\hdis.sql =>> {path}\\hdis.sql"); } else { Utility.SendLog("版本打包", $"未能找到数据库脚本:{$"{hospital.SCPath}\\src\\Document\\script\\hdis.sql"}"); return b_suc; } //压缩文件 Utility.SendLog("版本打包", $"压缩文件"); ZipHelper.ZipFiles(fname, $"{path}"); //清空缓存文件 Utility.SendLog("版本打包", $"清空缓存文件与文件夹"); dir = new DirectoryInfo(path); fileinfo = dir.GetFileSystemInfos(); //返回目录中所有文件和子目录 foreach (FileSystemInfo i in fileinfo) { if (i is DirectoryInfo) //判断是否文件夹 { DirectoryInfo subdir = new DirectoryInfo(i.FullName); subdir.Delete(true); //删除子目录和文件 } else { File.Delete(i.FullName); //删除指定文件 } } Directory.Delete(path); b_suc = true; Utility.SendLog("版本打包", $"生成数据库脚本完毕 {fname}"); return b_suc; } #endregion #region 采集插件打包 object m_InPulishTS = new object(); bool b_InPulishTS = false; private void tsmi_TSRelease_Click(object sender, EventArgs e) { lock (m_InPulishTS) { if (b_InPulishTS) { return; } } string flag = "采集插件"; bool b_build = false; string path = string.Empty; string tspath = string.Empty; string version = string.Empty; bool custom = false; string customHospitals = string.Empty; //选择路径和版本 using (Form_Plugin f = new Form_Plugin()) { f.ShowDialog(); if (f.m_DialogResult != DialogResult.Yes) { return; } b_build = f.m_Build; path = f.m_Path; version = f.m_Version; custom = f.m_Custom; customHospitals = f.m_CustomHospitals; tspath = f.m_TSPath; Utility.SendLog(flag, $"项目路径 {tspath}"); Utility.SendLog(flag, $"选择的路径 {path}"); Utility.SendLog(flag, $"输入的版本 {version}"); Utility.SendLog(flag, $"是否编译项目 {b_build}"); Utility.SendLog(flag, $"是否自定义医院 {custom} {(custom ? customHospitals : "")}"); } Utility.SendLog("开始生成采集插件", true); Thread t = new Thread(new ThreadStart(delegate { CreateTSPlugin(flag, b_build, path, tspath, version, custom, customHospitals); })); t.Start(); } void CreateTSPlugin(string flag, bool b_build, string path, string tspath, string version, bool custom, string customHospitals) { lock (m_InPulishTS) { b_InPulishTS = true; } try { //采集插件基础文件路径 string tsBasePath = $"{AppDomain.CurrentDomain.BaseDirectory.Replace("\\bin\\Debug\\", "")}\\ts"; //编译项目 if (b_build) { Utility.SendLog(flag, $"编译项目"); CmdHelper.ExecCmd($"cd {tspath}\\JianLian.Adapter.Center\\Host\\JianLian.Adapter.Hosting\r\n" + $"{tspath.Split(':')[0].Trim()}:\r\n" + $"dotnet publish -r linux-x64 --self-contained false -o .\\bin\\Release\\net5.0\\publish\r\n" + $"exit\r\n"); } List customs = custom ? customHospitals.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries).ToList() : new List(); //根据Custom\JianLian.Adapter.Hospital,创建医院文件夹 string customHospitalPath = $"{tspath}\\JianLian.Adapter.Center\\Custom"; System.IO.Directory.GetDirectories(customHospitalPath) .ToList() .ForEach(o => { //医院名称 var hospital = o.Substring(o.LastIndexOf('.') + 1); if (custom) { if (!customs.Contains(hospital)) { Utility.SendLog(flag, $"自定义生成,医院 {hospital} 丢弃"); return; } } var hospitalPath = $"{path}\\{hospital}\\{version}"; if (!System.IO.Directory.Exists(hospitalPath)) { System.IO.Directory.CreateDirectory(hospitalPath); } else { DeleteFilesItem(hospitalPath, new List { }); } //编译 if (b_build) { Utility.SendLog(flag, $"编译项目 {hospital}"); CmdHelper.ExecCmd($"cd {o}\r\n" + $"{tspath.Split(':')[0].Trim()}:\r\n" + $"dotnet build\r\n" + $"exit\r\n"); } Utility.SendLog(flag, $"正在生成医院 {hospital}"); if (!File.Exists($"{o}\\bin\\Debug\\net5.0\\Adapter.json")) { SendLog(flag, $"医院[{hospital}]配置文件 Adapter.json 不存在,不继续打包该医院"); return; } if (!File.Exists($"{o}\\bin\\Debug\\net5.0\\OtherDb.json")) { SendLog(flag, $"医院[{hospital}]配置文件 OtherDb.json 不存在,不继续打包该医院"); return; } if (!File.Exists($"{o}\\bin\\Debug\\net5.0\\appsettings.json")) { SendLog(flag, $"医院[{hospital}]配置文件 appsettings.json 不存在,不继续打包该医院"); return; } //拷贝插件基础文件 CopyDirectory(tsBasePath, hospitalPath, true); ////拷贝发布的文件到Code文件夹 //CopyDirectory($"{tspath}\\JianLian.Adapter.Center\\Host\\JianLian.Adapter.Hosting\\bin\\Release\\net5.0\\publish", $"{hospitalPath}\\code", true); //System.Threading.Thread.Sleep(1000); //拷贝本医院最新的dll文件和配置文件到Code文件夹 CopyDirectory($"{o}\\bin\\Debug\\net5.0", $"{hospitalPath}", true); System.Threading.Thread.Sleep(1000); //修改Adapter.json //var adaptercontent = File.ReadAllText($"{hospitalPath}\\code\\Adapter.json", Encoding.UTF8); //adaptercontent = adaptercontent.Replace($"JianLian.Adapter.Sample", $"JianLian.Adapter.{hospital}"); //File.WriteAllText($"{hospitalPath}\\code\\Adapter.json", adaptercontent, Encoding.UTF8); ////修改版本号 .env init.sh README.ihdis //var envcontent = File.ReadAllText($"{hospitalPath}\\.env", Encoding.UTF8); //envcontent = envcontent.Replace($"ts_TAG=base", $"ts_TAG={version}"); //File.WriteAllText($"{hospitalPath}\\.env", envcontent, Encoding.UTF8); //StringBuilder sb_init = new StringBuilder(); //File.ReadAllText($"{hospitalPath}\\init.sh", Encoding.UTF8) //.Replace("sudo docker tag hh/ts:base hh/ts:{$version}", $"sudo docker tag hh/ts:base hh/ts:{version}") //.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) //.ToList() //.ForEach(str => //{ // sb_init.Append($"{str}\n"); //}); //File.WriteAllText($"{hospitalPath}\\init.sh", sb_init.ToString(), Encoding.ASCII); var readmecontent = File.ReadAllText($"{hospitalPath}\\README.ihdis", Encoding.UTF8); readmecontent = readmecontent.Replace($"\"version\": \"base\",", $"\"version\": \"{version}\","); File.WriteAllText($"{hospitalPath}\\README.ihdis", readmecontent, Encoding.UTF8); //打包压缩文件 Utility.SendLog(flag, $"医院 {hospital} 开始压缩文件"); var zippath = hospitalPath.Substring(0, hospitalPath.LastIndexOf('\\')); ZipHelper.ZipFiles($"{zippath}\\ts.zip", hospitalPath); File.Copy($"{zippath}\\ts.zip", $"{hospitalPath}\\ts.zip"); File.Delete($"{zippath}\\ts.zip"); Utility.SendLog(flag, $"医院 {hospital} 开始清理缓存文件"); DeleteFilesItem(hospitalPath, new List { $"{hospitalPath}\\ts.zip" }); Utility.SendLog(flag, $"医院 {hospital} 生成完毕"); }); Utility.SendLog(flag, $"生成完毕", true); } catch (Exception ex) { MessageBox.Show($"生成失败:{ex}"); } finally { lock (m_InPulishTS) b_InPulishTS = false; } } /// /// 删除全部文件 /// /// /// 例外的目录 /// 例外的文件 private void DeleteFilesItem(string path, List fileExceptions) { var fs = Directory.GetFiles(path); fs.ToList().ForEach(filename => { if (fileExceptions.Contains(filename)) return; File.Delete(filename); }); var ds = Directory.GetDirectories(path); ds.ToList().ForEach(o => { DeleteFilesItem(o, fileExceptions); }); //清除空目录 fs = Directory.GetFiles(path); if (fs.Length == 0) { Directory.Delete(path); } } private static bool CopyDirectory(string sourcePath, string destinationPath, bool overwriteexisting) { bool ret = false; try { sourcePath = sourcePath.EndsWith(@"\") ? sourcePath : sourcePath + @"\"; destinationPath = destinationPath.EndsWith(@"\") ? destinationPath : destinationPath + @"\"; if (Directory.Exists(sourcePath)) { if (Directory.Exists(destinationPath) == false) Directory.CreateDirectory(destinationPath); foreach (string fls in Directory.GetFiles(sourcePath)) { FileInfo flinfo = new FileInfo(fls); flinfo.CopyTo(destinationPath + flinfo.Name, overwriteexisting); } foreach (string drs in Directory.GetDirectories(sourcePath)) { DirectoryInfo drinfo = new DirectoryInfo(drs); if (CopyDirectory(drs, destinationPath + drinfo.Name, overwriteexisting) == false) ret = false; } } ret = true; } catch { ret = false; } return ret; } #endregion #region 升级日志 private void tsmi_UpgradeLog_Click(object sender, EventArgs e) { using (Form_UpgradeLog f = new Form_UpgradeLog()) { f.ShowDialog(); } } #endregion #region 数据库管理 private void tsmi_HeidiSQL_Click(object sender, EventArgs e) { if (!HasSelectdHospital(out DevServer server, out Hospital hospital)) { return; } if (!SftpHelper.Exists(server, $"/home/{server.UserName}/ihdis/compose/{hospital.FileName}") && !SftpHelper.Exists(server, $"/home/{server.UserName}/ihdis/{hospital.FileName}")) { MessageBox.Show("医院不存在", "提示"); return; } string heidisql = @"C:\Program Files\HeidiSQL\heidisql.exe"; if (!File.Exists(heidisql)) { MessageBox.Show($"未能检测到 [HeidiSQL],请先安装!\r\n默认检测路径为:{heidisql}", "提示"); } else { if (hospital.FileName == "produse") { System.Diagnostics.Process.Start(heidisql, $" -d {server.Ip}({hospital.FileName}) -n {0} -h {server.Ip} -u root -p jlmed#123 -P {hospital.DefaultFort}90"); } else { System.Diagnostics.Process.Start(heidisql, $" -d {server.Ip}({hospital.FileName}) -n {0} -h {server.Ip} -u root -p jlmed#123 -P {hospital.DefaultFort}90"); } } } #endregion #region 关于 private void tsmi_About_Click(object sender, EventArgs e) { using (Form_About f = new Form_About()) { f.ShowDialog(); } } #endregion #region 前端代码生成 private void tsmi_CodeGeneRATOR_Click(object sender, EventArgs e) { using (Form_CodeGenerator f = new Form_CodeGenerator()) { f.ShowDialog(); } } #endregion } }