2021年1月

LAMP 套件是一种流行的开源 Web 开发平台,可用于运行和部署动态网站和基于 Web 的应用程序。通常,LAMP 套件由 Apache Web 服务器、MariaDB/MySQL 数据库、PHP/Python/Perl 程序设计(脚本)语言组成。 LAMP 是 Linux,MariaDB/MYSQL,PHP/Python/Perl 的缩写。 本教程描述了如何在 Ubuntu 18.04 LTS 服务器中安装 Apache、MySQL、PHP(LAMP 套件)。

就本教程而言,我们将使用以下 Ubuntu 测试。

  • 操作系统:Ubuntu 18.04.1 LTS Server Edition
  • IP 地址 :192.168.225.22/24

1. 安装 Apache Web 服务器

首先,利用下面命令更新 Ubuntu 服务器:

$ sudo apt update
$ sudo apt upgrade

然后,安装 Apache Web 服务器(命令如下):

$ sudo apt install apache2

检查 Apache Web 服务器是否已经运行:

$ sudo systemctl status apache2

输出结果大概是这样的:

● apache2.service - The Apache HTTP Server
 Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: en
 Drop-In: /lib/systemd/system/apache2.service.d
 └─apache2-systemd.conf
 Active: active (running) since Tue 2019-02-05 10:48:03 UTC; 1min 5s ago
 Main PID: 2025 (apache2)
 Tasks: 55 (limit: 2320)
 CGroup: /system.slice/apache2.service
 ├─2025 /usr/sbin/apache2 -k start
 ├─2027 /usr/sbin/apache2 -k start
 └─2028 /usr/sbin/apache2 -k start

Feb 05 10:48:02 ubuntuserver systemd[1]: Starting The Apache HTTP Server...
Feb 05 10:48:03 ubuntuserver apachectl[2003]: AH00558: apache2: Could not reliably
Feb 05 10:48:03 ubuntuserver systemd[1]: Started The Apache HTTP Server.

祝贺你! Apache 服务已经启动并运行了!!

1.1 调整防火墙允许 Apache Web 服务器

默认情况下,如果你已在 Ubuntu 中启用 UFW 防火墙,则无法从远程系统访问 Apache Web 服务器。 必须按照以下步骤开启 httphttps 端口。

首先,使用以下命令列出 Ubuntu 系统上可用的应用程序配置文件:

$ sudo ufw app list

输出结果:

Available applications:
Apache
Apache Full
Apache Secure
OpenSSH

如你所见,Apache 和 OpenSSH 应用程序已安装 UFW 配置文件。你可以使用 ufw app info "Profile Name" 命令列出有关每个配置文件及其包含的规则的信息。

让我们研究一下 “Apache Full” 配置文件。 为此,请运行:

$ sudo ufw app info "Apache Full"

输出结果:

Profile: Apache Full
Title: Web Server (HTTP,HTTPS)
Description: Apache v2 is the next generation of the omnipresent Apache web
server.

Ports:
80,443/tcp

如你所见,“Apache Full” 配置文件包含了启用经由端口 80443 的传输规则:

现在,运行以下命令配置允许 HTTP 和 HTTPS 传入通信:

$ sudo ufw allow in "Apache Full"
Rules updated
Rules updated (v6)

如果你不想允许 HTTP 通信,而只允许 HTTP(80) 通信,请运行:

$ sudo ufw app info "Apache"

1.2 测试 Apache Web 服务器

现在,打开 Web 浏览器并导航到 http://localhost/或http://IP-Address/ 来访问 Apache 测试页。

如果看到上面类似的显示内容,那就成功了。 Apache 服务器正在工作!

2. 安装 MySQL

在 Ubuntu 安装 MySQL 请运行:

$ sudo apt install mysql-server

使用以下命令验证 MySQL 服务是否正在运行:

$ sudo systemctl status mysql

输出结果:

● mysql.service - MySQL Community Server
Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset: enab
Active: active (running) since Tue 2019-02-05 11:07:50 UTC; 17s ago
Main PID: 3423 (mysqld)
Tasks: 27 (limit: 2320)
CGroup: /system.slice/mysql.service
└─3423 /usr/sbin/mysqld --daemonize --pid-file=/run/mysqld/mysqld.pid

Feb 05 11:07:49 ubuntuserver systemd[1]: Starting MySQL Community Server...
Feb 05 11:07:50 ubuntuserver systemd[1]: Started MySQL Community Server.

MySQL 正在运行!

2.1 配置数据库管理用户(root)密码

默认情况下,MySQL root 用户密码为空。你需要通过运行以下脚本使你的 MySQL 服务器安全:

$ sudo mysql_secure_installation

系统将询问你是否要安装 “VALIDATE PASSWORD plugin(密码验证插件)”。该插件允许用户为数据库配置强密码凭据。如果启用,它将自动检查密码的强度并强制用户设置足够安全的密码。禁用此插件是安全的。但是,必须为数据库使用唯一的强密码凭据。如果不想启用此插件,只需按任意键即可跳过密码验证部分,然后继续其余步骤。

如果回答是 y,则会要求你选择密码验证级别。

Securing the MySQL server deployment.

Connecting to MySQL using a blank password.

VALIDATE PASSWORD PLUGIN can be used to test passwords
and improve security. It checks the strength of password
and allows the users to set only those passwords which are
secure enough. Would you like to setup VALIDATE PASSWORD plugin?

Press y|Y for Yes, any other key for No y

可用的密码验证有 “low(低)”、 “medium(中)” 和 “strong(强)”。只需输入适当的数字(0 表示低,1 表示中,2 表示强密码)并按回车键。

There are three levels of password validation policy:

LOW Length >= 8
MEDIUM Length >= 8, numeric, mixed case, and special characters
STRONG Length >= 8, numeric, mixed case, special characters and dictionary file

Please enter 0 = LOW, 1 = MEDIUM and 2 = STRONG:

现在,输入 MySQL root 用户的密码。请注意,必须根据上一步中选择的密码策略,为 MySQL root 用户使用密码。如果你未启用该插件,则只需使用你选择的任意强度且唯一的密码即可。

Please set the password for root here.

New password:

Re-enter new password:

Estimated strength of the password: 50
Do you wish to continue with the password provided?(Press y|Y for Yes, any other key for No) : y

两次输入密码后,你将看到密码强度(在此示例情况下为 50)。如果你确定可以,请按 y 继续提供的密码。如果对密码长度不满意,请按其他任意键并设置一个强密码。我现在的密码可以,所以我选择了y

对于其余的问题,只需键入 y 并按回车键。这将删除匿名用户、禁止 root 用户远程登录并删除 test(测试)数据库。

Remove anonymous users? (Press y|Y for Yes, any other key for No) : y
Success.

Normally, root should only be allowed to connect from
'localhost'. This ensures that someone cannot guess at
the root password from the network.

Disallow root login remotely? (Press y|Y for Yes, any other key for No) : y
Success.

By default, MySQL comes with a database named 'test' that
anyone can access. This is also intended only for testing,
and should be removed before moving into a production
environment.

Remove test database and access to it? (Press y|Y for Yes, any other key for No) : y
- Dropping test database...
Success.

- Removing privileges on test database...
Success.

Reloading the privilege tables will ensure that all changes
made so far will take effect immediately.

Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y
Success.

All done!

以上就是为 MySQL root 用户设置密码。

2.2 更改 MySQL 超级用户的身份验证方法

默认情况下,Ubuntu 系统的 MySQL root 用户为 MySQL 5.7 版本及更新的版本使用插件 auth_socket 设置身份验证。尽管它增强了安全性,但是当你使用任何外部程序(例如 phpMyAdmin)访问数据库服务器时,也会变得更困难。要解决此问题,你需要将身份验证方法从 auth_socket 更改为 mysql_native_password。为此,请使用以下命令登录到你的 MySQL 提示符下:

$ sudo mysql

在 MySQL 提示符下运行以下命令,找到所有 MySQL 当前用户帐户的身份验证方法:

SELECT user,authentication_string,plugin,host FROM mysql.user;

输出结果:

+------------------|-------------------------------------------|-----------------------|-----------+
| user | authentication_string | plugin | host |
+------------------|-------------------------------------------|-----------------------|-----------+
| root | | auth_socket | localhost |
| mysql.session | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE | mysql_native_password | localhost |
| mysql.sys | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE | mysql_native_password | localhost |
| debian-sys-maint | *F126737722832701DD3979741508F05FA71E5BA0 | mysql_native_password | localhost |
+------------------|-------------------------------------------|-----------------------|-----------+
4 rows in set (0.00 sec)

如你所见,Mysql root 用户使用 auth_socket 插件进行身份验证。

要将此身份验证更改为 mysql_native_password 方法,请在 MySQL 提示符下运行以下命令。 别忘了用你选择的强大唯一的密码替换 password。 如果已启用 VALIDATION 插件,请确保已根据当前策略要求使用了强密码。

ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';

使用以下命令更新数据库:

FLUSH PRIVILEGES;

使用命令再次检查身份验证方法是否已更改:

SELECT user,authentication_string,plugin,host FROM mysql.user;

输出结果:

好!MySQL root 用户就可以使用密码进行身份验证来访问 mysql shell

从 MySQL 提示符下退出:

exit

3. 安装 PHP

安装 PHP 请运行:

$ sudo apt install php libapache2-mod-php php-mysql

安装 PHP 后,在 Apache 文档根目录中创建 info.php 文件。通常,在大多数基于 Debian 的 Linux 发行版中,Apache 文档根目录为 /var/www/html//var/www/。Ubuntu 18.04 LTS 系统下,文档根目录是 /var/www/html/

在 Apache 根目录中创建 info.php 文件:

$ sudo vi /var/www/html/info.php

在此文件中编辑如下内容:

<?php
phpinfo();
?>

然后按下 ESC 键并且输入 :wq 保存并退出此文件。重新启动 Apache 服务使更改生效。

$ sudo systemctl restart apache2

3.1 测试 PHP

打开 Web 浏览器,然后导航到 URL http://IP地址/info.php

你就将看到 PHP 测试页面。

通常,当用户向 Web 服务器发出请求时,Apache 首先会在文档根目录中查找名为 index.html 的文件。如果你想将 Apache 更改为 php 文件提供服务而不是其他文件,请将 dir.conf 配置文件中的 index.php 移至第一个位置,如下所示:

$ sudo vi /etc/apache2/mods-enabled/dir.conf

上面的配置文件(dir.conf) 内容如下:

<IfModule mod_dir.c>
DirectoryIndex index.html index.cgi index.pl index.php index.xhtml index.htm
</IfModule>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

index.php 移动到最前面。更改后,dir.conf 文件内容看起来如下所示。

<IfModule mod_dir.c>
DirectoryIndex index.php index.html index.cgi index.pl index.xhtml index.htm
</IfModule>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

然后按下 ESC 键并且输入 :wq 保存并关闭此文件。重新启动 Apache 服务使更改生效。

$ sudo systemctl restart apache2

3.2 安装 PHP 模块

为了增加 PHP 的功能,可以安装一些其他的 PHP 模块。

要列出可用的 PHP 模块,请运行:

$ sudo apt-cache search php- | less

输出结果:

使用方向键浏览结果。要退出,请输入 q 并按下回车键。

要查找任意 php 模块的详细信息,例如 php-gd,请运行:

$ sudo apt-cache show php-gd

安装 PHP 模块请运行:

$ sudo apt install php-gd

安装所有的模块(虽然没有必要),请运行:

$ sudo apt-get install php*

安装任何 php 模块后,请不要忘记重新启动 Apache 服务。要检查模块是否已加载,请在浏览器中打开 info.php 文件并检查是否存在。

接下来,你可能需要安装数据库管理工具,以通过 Web 浏览器轻松管理数据库。如果是这样,请按照以下链接中的说明安装 phpMyAdmin

祝贺你!我们已经在 Ubuntu 服务器中成功配置了 LAMP 套件。


via: https://www.ostechnix.com/install-apache-mysql-php-lamp-stack-on-ubuntu-18-04-lts/

作者:SK 选题:lujun9972 译者:stevenzdg988 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

软件如果不能被电脑运行,那么它就是无用的。而在处理 运行时 run-time 性能的问题上,即使是最有才华的开发人员也会受编译器的支配 —— 因为如果没有可靠的编译器工具链,就无法构建任何重要的东西。 GNU 编译器集合 GNU Compiler Collection (GCC)提供了一个健壮、成熟和高性能的工具,以帮助你充分发挥你代码的潜能。经过数十年成千上万人的开发,GCC 成为了世界上最受尊敬的编译器之一。如果你在构建应用程序是没有使用 GCC,那么你可能错过了最佳解决方案。

根据 LLVM.org 的说法,GCC 是“如今事实上的标准开源编译器” [1] ,也是用来构建完整系统的基础 —— 从内核开始。GCC 支持超过 60 种硬件平台,包括 ARM、Intel、AMD、IBM POWER、SPARC、HP PA-RISC 和 IBM Z,以及各种操作环境,包括 GNU、Linux、Windows、macOS、FreeBSD、NetBSD、OpenBSD、DragonFly BSD、Solaris、AIX、HP-UX 和 RTEMS。它提供了高度兼容的 C/C++ 编译器,并支持流行的 C 库,如 GNU C Library(glibc)、Newlib、musl 和各种 BSD 操作系统中包含的 C 库,以及 Fortran、Ada 和 GO 语言的前端。GCC 还可以作为一个交叉编译器,可以为运行编译器的平台以外的其他平台创建可执行代码。GCC 是紧密集成的 GNU 工具链的核心组件,由 GNU 项目产生,它包括 glibc、Binutils 和 GNU 调试器(GDB)。

“一直以来我最喜欢的 GNU 工具是 GCC,即 GNU 编译器集合 GNU Compiler Collection 。在开发工具非常昂贵的时候,GCC 是第二个 GNU 工具,也是使社区能够编写和构建所有其他工具的工具。这个工具一手改变了这个行业,导致了自由软件运动的诞生,因为一个好的、自由的编译器是一个社区软件的先决条件。”—— Red Hat 开源和标准团队的 Dave Neary。 [2]

优化 Linux

作为 Linux 内核源代码的默认编译器,GCC 提供了可靠、稳定的性能以及正确构建内核所需的额外扩展。GCC 是流行的 Linux 发行版的标准组件,如 ArchLinux、CentOS、Debian、Fedora、openSUSE 和 Ubuntu 这些发行版中,GCC 通常用来编译支持系统的组件。这包括 Linux 使用的默认库(如 libc、libm、libintl、libssh、libssl、libcrypto、libexpat、libpthread 和 ncurses),这些库依赖于 GCC 来提供可靠性和高性能,并且使应用程序和系统程序可以访问 Linux 内核功能。发行版中包含的许多应用程序包也是用 GCC 构建的,例如 Python、Perl、Ruby、nginx、Apache HTTP 服务器、OpenStack、Docker 和 OpenShift。各个 Linux 发行版使用 GCC 构建的大量代码组成了内核、库和应用程序软件。对于 openSUSE 发行版,几乎 100% 的原生代码都是由 GCC 构建的,包括 6135 个源程序包、5705 个共享库和 38927 个可执行文件。这相当于每周编译 24540 个源代码包。 [3]

Linux 发行版中包含的 GCC 的基本版本用于创建定义系统 应用程序二进制接口 Application Binary Interface (ABI)的内核和库。 用户空间 User space 开发者可以选择下载 GCC 的最新稳定版本,以获得高级功能、性能优化和可用性改进。Linux 发行版提供安装说明或预构建的工具链,用于部署最新版本的 GCC 以及其他 GNU 工具,这些工具有助于提高开发人员的工作效率和缩短部署时间。

优化互联网

GCC 是嵌入式系统中被广泛采用的核心编译器之一,支持为日益增长的物联网设备开发软件。GCC 提供了许多扩展功能,使其非常适合嵌入式系统软件开发,包括使用编译器的内建函数、#语法、内联汇编和以应用程序为中心的命令行选项进行精细控制。GCC 支持广泛的嵌入式体系结构,包括 ARM、AMCC、AVR、Blackfin、MIPS、RISC-V、Renesas Electronics V850、NXP 和 Freescale Power 处理器,可以生成高效、高质量的代码。GCC提供的交叉编译能力对这个社区至关重要,而预制的交叉编译工具链 [4] 是一个主要需求。例如,GNU ARM 嵌入式工具链是经过集成和验证的软件包,其中包含 ARM 嵌入式 GCC 编译器、库和其它裸机软件开发所需的工具。这些工具链可用于在 Windows、Linux 和 macOS 主机操作系统上对流行的 ARM Cortex-R 和 Cortex-M 处理器进行交叉编译,这些处理器已装载于数百亿台支持互联网的设备中。 [5]

GCC 为云计算赋能,为需要直接管理计算资源的软件提供了可靠的开发平台,如数据库和 Web 服务引擎以及备份和安全软件。GCC 完全兼容 C++ 11 和 C++ 14,为 C++ 17 和 C++ 2a 提供实验支持 [6] (LCTT 译注:本文原文发布于 2018 年),可以创建性能优异的对象代码,并提供可靠的调试信息。使用 GCC 的应用程序的一些例子包括:MySQL 数据库管理系统,它需要 Linux 的 GCC [7] ;Apache HTTP 服务器,它建议使用 GCC [8] ;Bacula,一个企业级网络备份工具,它需要 GCC。 [9]

优化一切

对于 高性能计算 High Performance Computing (HPC)中使用的科学代码的研究和开发,GCC 提供了成熟的 C、C++ 和 Fortran 前端,以及对 OpenMP 和 OpenACC API的支持,用于基于指令的并行编程。因为 GCC 提供了跨计算环境的可移植性,它使得代码能够更容易地在各种新的和传统的客户机和服务器平台上进行测试。GCC 为 C、C++ 和 Fortran 编译器提供了 OpenMP 4.0 的完整支持,为 C 和 C++ 编译器提供了 OpenMP 4.5 完整支持。对于 OpenACC、 GCC 支持大部分 2.5 规范和性能优化,并且是唯一提供 OpenACC 支持的非商业、非学术编译器。

代码性能是这个社区的一个重要参数,GCC 提供了一个坚实的性能基础。Colfax Research 于 2017 年 11 月发表的一篇论文评估了 C++ 编译器在使用 OpenMP 4.x 指令并行化编译代码的速度和编译后代码的运行速度。图 1 描绘了不同编译器编译并使用单个线程运行时计算内核的相对性能。性能值经过了归一化处理,以 G++ 的性能为 1.0。

 title=

图 1 为由不同编译器编译的每个内核的相对性能。(单线程,越高越好)。

他的论文总结道:“GNU 编译器在我们的测试中也做得很好。G++ 在六种情况中的三种情况下生成的代码速度是第二快的,并且在编译时间方面是最快的编译器之一。” [10]

谁在用 GCC?

在 JetBrains 2018 年的开发者生态状况调查中,在接受调查的 6000 名开发者中,66% 的 C++ 程序员和 73% 的 C 程序员经常使用 GCC。 [11] 以下简要介绍 GCC 的优点,正是这些优点使它在开发人员社区中如此受欢迎。

  • 对于需要为各种新的和遗留的计算平台和操作环境编写代码的开发人员,GCC 提供了对最广泛的硬件和操作环境的支持。硬件供应商提供的编译器主要侧重于对其产品的支持,而其他开源编译器在所支持的硬件和操作系统方面则受到很大限制。 [12]
  • 有各种各样的基于 GCC 的预构建工具链,这对嵌入式系统开发人员特别有吸引力。这包括 GNU ARM 嵌入式工具链和 Bootlin 网站上提供的 138 个预编译交叉编译器工具链。 [13] 虽然其他开源编译器(如 Clang/LLVM)可以取代现有交叉编译工具链中的 GCC,但这些工具集需要开发者完全重新构建。 [14]
  • GCC 通过成熟的编译器平台向应用程序开发人员提供可靠、稳定的性能。《在 AMD EPYC 平台上用 GCC 8/9 与 LLVM Clang 6/7 编译器基准测试》这篇文章提供了 49 个基准测试的结果,这些测试的编译器在三个优化级别上运行。使用 -O3 -march=native 级别的 GCC 8.2 RC1 在 34% 的时间里排在第一位,而在相同的优化级别 LLVM Clang 6.0 在 20% 的时间里赢得了第二位。 [15]
  • GCC 为编译调试 [16] 提供了改进的诊断方法,并为运行时调试提供了准确而有用的信息。GCC 与 GDB 紧密集成,GDB 是一个成熟且功能齐全的工具,它提供“不间断”调试,可以在断点处停止单个线程。
  • GCC 是一个得到良好支持的平台,它有一个活跃的、有责任感的社区,支持当前版本和以前的两个版本。由于每年都有发布计划,这为一个版本提供了两年的支持。

GCC:仍然在继续优化

GCC 作为一个世界级的编译器继续向前发展。GCC 的最新版本是 8.2,于 2018 年 7 月发布(LCTT 译注:本文原文发表于 2018 年),增加了对即将推出的 Intel CPU、更多 ARM CPU 的硬件支持,并提高了 AMD 的 ZEN CPU 的性能。增加了对 C17 的初步支持,同时也对 C++2A 进行了初步工作。诊断功能继续得到增强,包括更好的发射诊断,改进了定位、定位范围和修复提示,特别是在 C++ 前端。Red Hat 的 David Malcolm 在 2018 年 3 月撰写的博客概述了 GCC 8 中的可用性改进。 [17]

新的硬件平台继续依赖 GCC 工具链进行软件开发,例如 RISC-V,这是一种自由开放的 ISA,机器学习、人工智能(AI)和物联网细分市场都对其感兴趣。GCC 仍然是 Linux 系统持续开发的关键组件。针对 Intel 架构的 Clear Linux 项目是一个为云、客户端和物联网用例构建的新兴发行版,它提供了一个很好的示例,说明如何使用和改进 GCC 编译器技术来提高基于 Linux 的系统的性能和安全性。GCC 还被用于微软 Azure Sphere 的应用程序开发,这是一个基于 Linux 的物联网应用程序操作系统,最初支持基于 ARM 的联发科 MT3620 处理器。在培养下一代程序员方面,GCC 也是树莓派的 Windows 工具链的核心组件,树莓派是一种运行基于 Debian 的 GNU/Linux 的低成本嵌入式板,用于促进学校和发展中国家的基础计算机科学教学。

GCC 由 GNU 项目的创始人 理查德•斯托曼 Richard Stallman 首次发布 于 1987 年 3 月 22 日,由于它是第一个作为自由软件发布的可移植的 ANSI C 优化编译器,因此它被认为是一个重大突破。GCC 由来自世界各地的程序员组成的社区在指导委员会的指导下维护,以确保对项目进行广泛的、有代表性的监督。GCC 的社区方法是它的优势之一,它形成了一个由开发人员和用户组成的庞大而多样化的社区,他们为项目做出了贡献并提供支持。根据 Open Hub 的说法,“GCC 是世界上最大的开源团队之一,在 Open Hub 上的所有项目团队中排名前 2%。” [18]

关于 GCC 的许可问题,人们进行了大量的讨论,其中大多数是混淆而不是启发。GCC 在 GNU 通用公共许可证(GPL)版本 3 或更高版本下发布,但运行时库例外。这是一个左版许可,这意味着衍生作品只能在相同的许可条款下分发。GPLv3 旨在保护 GCC,防止其成为专有软件,并要求对 GCC 代码的更改可以自由公开地进行。对于“最终用户”来说,这个编译器与其他编译器完全相同;使用 GCC 对你为自己的代码所选择的任何许可都没有区别。 [19]


  1. http://clang.llvm.org/features.html#gcccompat ↩︎
  2. https://opensource.com/article/18/9/happy-birthday-gnu ↩︎
  3. 由 SUSE 基于最近的构建统计提供的信息。在 openSUSE 中还有其他不生成可执行镜像的源码包,这些不包括在统计中。 ↩︎
  4. https://community.arm.com/tools/b/blog/posts/gnu-toolchain-performance-in-2018 ↩︎
  5. https://www.arm.com/products/processors/cortex-m ↩︎
  6. https://gcc.gnu.org/projects/cxx-status.html#cxx17 ↩︎
  7. https://mysqlserverteam.com/mysql-8-0-source-code-improvements/ ↩︎
  8. http://httpd.apache.org/docs/2.4/install.html ↩︎
  9. https://blog.bacula.org/what-is-bacula/system-requirements/ ↩︎
  10. https://colfaxresearch.com/compiler-comparison/ ↩︎
  11. https://www.jetbrains.com/research/devecosystem-2018/ ↩︎
  12. http://releases.llvm.org/6.0.0/tools/clang/docs/UsersManual.html ↩︎
  13. https://bootlin.com/blog/free-and-ready-to-use-cross-compilation-toolchains/ ↩︎
  14. https://clang.llvm.org/docs/Toolchain.html ↩︎
  15. https://www.phoronix.com/scan.php?page=article&item=gcclang-epyc-summer18&num=1 ↩︎
  16. https://gcc.gnu.org/wiki/ClangDiagnosticsComparison ↩︎
  17. https://developers.redhat.com/blog/2018/03/15/gcc-8-usability-improvements/ ↩︎
  18. https://www.openhub.net/p/gcc/factoids#FactoidTeamSizeVeryLarge ↩︎
  19. https://www.gnu.org/licenses/gcc-exception-3.1-faq.en.html ↩︎

via: https://www.linux.com/blog/2018/10/gcc-optimizing-linux-internet-and-everything

作者:Margaret Lewis 选题:lujun9972 译者:Chao-zhi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

有时候,除你自己外,没有人能制作你所梦想的工具。以下是如何开始构建你自己的文本编辑器。

 title=

有很多文本编辑器。有运行在终端中、运行在 GUI 中、运行在浏览器和浏览器引擎中的。有很多是还不错,有一些则是极好的。但是有时候,毫无疑问,最令人满意的就是你自己构建的编辑器。

毫无疑问:构建一个真正优秀的文本编辑器比表面上看上去要困难得多。但话说回来,建立一个基本的文本编辑器也不像你担心的那样难。事实上,大多数编程工具包已经为你准备好了文本编辑器的大部分组件。围绕文本编辑的组件,例如菜单条,文件选择对话框等等,是很容易落到实处。因此,虽然是中级的编程课程,但构建一个基本的文本编辑器是出乎意料的有趣和简明。你可能会发现自己渴望使用一个自己构造的工具,而且你使用得越多,你可能会有更多的灵感来增加它的功能,从而更多地学习你正在使用的编程语言。

为了使这个练习切合实际,最好选择一种具有令人满意的 GUI 工具箱的语言。有很多种选择,包括 Qt 、FLTK 或 GTK ,但是一定要先评审一下它的文档,以确保它有你所期待的功能。对于这篇文章来说,我使用 Java 以及其内置的 Swing 小部件集。如果你想使用一种不同的语言或者一种不同的工具集,这篇文章在如何帮你处理这种问题的方面也仍然是有用的。

不管你选择哪一种,在任何主要的工具箱中编写一个文本编辑器都是惊人的相似。如果你是 Java 新手,需要更多关于开始的信息,请先阅读我的 猜谜游戏文章

工程设置

通常,我使用并推荐像 Netbeans 或 Eclipse 这样的 IDE,但我发现,当学习一种新的语言时,手工做一些工作是很有帮助的,这样你就能更好地理解使用 IDE 时被隐藏起来的东西。在这篇文章中,我假设你正在使用文本编辑器和终端进行编程。

在开始前,为你自己的工程创建一个工程目录。在工程文件夹中,创建一个名称为 src 的目录来容纳你的源文件。

$ mkdir -p myTextEditor/src
$ cd myTextEditor

在你的 src 目录中创建一个名称为 TextEdit.java 的空白的文件:

$ touch src/TextEditor.java

在你最喜欢的文本编辑器中打开这个空白的文件(我的意思是除你自己编写之外的最喜欢的一款文本编辑器),然后准备好编码吧!

包和导入

为确保你的 Java 应用程序有一个唯一的标识符,你必须声明一个 package 名称。典型的格式是使用一个反向的域名,如果你真的有一个域名的话,这就特别容易了。如果你没有域名的话,你可以使用 local 作为最顶层。像 Java 和很多语言一样,行以分号结尾。

在命名你的 Java 的 package 后,你必须告诉 Java 编译器(javac)使用哪些库来构建你的代码。事实上,这通常是你边编写代码边添加的内容,因为你很少事先知道你自己所需要的库。然而,这里有一些库是显而易见的。例如,你知道这个文本编辑器是基于 Swing GUI 工具箱的,因此,导入 javax.swing.JFramejavax.swing.UIManager 和其它相关的特定库。

package com.example.textedit;

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.filechooser.FileSystemView;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;

对于这个练习的目标,你可以提前预知你所需要的所有的库。在真实的生活中,不管你喜欢哪一种语言,你都将在研究如何解决一些问题的时候发现库,然后,你将它导入到你的代码中,并使用它。不需要担心 —— 如果你忘记包含一个库,你的编译器或解释器将警告你!

主窗口

这是一个单窗口应用程序,因此这个应用程序的主类是一个 JFrame ,其附带有一个捕捉菜单事件的 ActionListener 。在 Java 中,当你使用一个现有的小部件元素时,你可以使用你的代码“扩展”它。这个主窗口需要三个字段:窗口本身(一个 JFrame 的实例)、一个用于文件选择器返回值的标识符和文本编辑器本身(JTextArea)。

public final class TextEdit extends JFrame implements ActionListener {
private static JTextArea area;
private static JFrame frame;
private static int returnValue = 0;

令人惊奇的是,这数行代码完成了实现一个基本文本编辑器的 80% 的工作,因为 JtextArea 是 Java 的文本输入字段。剩下的 80 行代码大部分用于处理辅助功能,比如保存和打开文件。

构建一个菜单

JMenuBar 小部件被设计到 JFrame 的顶部,它为你提供你想要的很多菜单项。Java 不是一种 拖放式的编程语言,因此,对于你所添加的每一个菜单,你都还必须编写一个函数。为保持这个工程的可控性,我提供了四个函数:创建一个新的文件,打开一个现有的文件,保存文本到一个文件,和关闭应用程序。

在大多数流行的工具箱中,创建一个菜单的过程基本相同。首先,你创建菜单条本身,然后创建一个顶级菜单(例如 “File” ),再然后创建子菜单项(例如,“New”、“Save” 等)。

public TextEdit() { run(); }

public void run() {
    frame = new JFrame("Text Edit");

    // Set the look-and-feel (LNF) of the application
    // Try to default to whatever the host system prefers
    try {
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
      Logger.getLogger(TextEdit.class.getName()).log(Level.SEVERE, null, ex);
    }

    // Set attributes of the app window
    area = new JTextArea();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.add(area);
    frame.setSize(640, 480);
    frame.setVisible(true);

    // Build the menu
    JMenuBar menu_main = new JMenuBar();

    JMenu menu_file = new JMenu("File");

    JMenuItem menuitem_new = new JMenuItem("New");
    JMenuItem menuitem_open = new JMenuItem("Open");
    JMenuItem menuitem_save = new JMenuItem("Save");
    JMenuItem menuitem_quit = new JMenuItem("Quit");

    menuitem_new.addActionListener(this);
    menuitem_open.addActionListener(this);
    menuitem_save.addActionListener(this);
    menuitem_quit.addActionListener(this);

    menu_main.add(menu_file);

    menu_file.add(menuitem_new);
    menu_file.add(menuitem_open);
    menu_file.add(menuitem_save);
    menu_file.add(menuitem_quit);

    frame.setJMenuBar(menu_main);
    }

现在,所有剩余的工作是实施菜单项所描述的功能。

编程菜单动作

你的应用程序响应菜单选择,是因为你的 JFrame 有一个附属于它的 ActionListener 。在 Java 中,当你实施一个事件处理程序时,你必须“重写”其内建的函数。这只是听起来可怕。你不是在重写 Java;你只是在实现已经被定义但尚未实施事件处理程序的函数。

在这种情况下,你必须重写 actionPerformed方法。因为在 “File” 菜单中的所有条目都与处理文件有关,所以在我的代码中很早就定义了一个 JFileChooser 。代码其它部分被划分到一个 if 语句的子语句中,这起来像接收到什么事件就相应地执行什么动作。每个子语句都与其它的子语句完全不同,因为每个项目都标示着一些完全唯一的东西。最相似的是 “Open” 和 “Save”,因为它们都使用 JFileChooser 选择文件系统中的一个位置来获取或放置数据。

“New” 菜单会在没有警告的情况下清理 JTextArea ,“Quit” 菜单会在没有警告的情况下关闭应用程序。这两个 “功能” 都是不安全的,因此你应该想对这段代码进行一点改善,这是一个很好的开始。在内容还没有被保存前,一个友好的警告是任何一个好的文本编辑器都必不可少的一个功能,但是在这里为了简单,这是未来的一个功能。

@Override
public void actionPerformed(ActionEvent e) {
    String ingest = null;
    JFileChooser jfc = new JFileChooser(FileSystemView.getFileSystemView().getHomeDirectory());
    jfc.setDialogTitle("Choose destination.");
    jfc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);

    String ae = e.getActionCommand();
    if (ae.equals("Open")) {
        returnValue = jfc.showOpenDialog(null);
        if (returnValue == JFileChooser.APPROVE_OPTION) {
        File f = new File(jfc.getSelectedFile().getAbsolutePath());
        try{
            FileReader read = new FileReader(f);
            Scanner scan = new Scanner(read);
            while(scan.hasNextLine()){
                String line = scan.nextLine() + "\n";
                ingest = ingest + line;
        }
            area.setText(ingest);
        }
    catch ( FileNotFoundException ex) { ex.printStackTrace(); }
}
    // 保存
    } else if (ae.equals("Save")) {
        returnValue = jfc.showSaveDialog(null);
        try {
            File f = new File(jfc.getSelectedFile().getAbsolutePath());
            FileWriter out = new FileWriter(f);
            out.write(area.getText());
            out.close();
        } catch (FileNotFoundException ex) {
            Component f = null;
            JOptionPane.showMessageDialog(f,"File not found.");
        } catch (IOException ex) {
            Component f = null;
            JOptionPane.showMessageDialog(f,"Error.");
        }
    } else if (ae.equals("New")) {
        area.setText("");
    } else if (ae.equals("Quit")) { System.exit(0); }
  }
}

从技术上来说,这就是这个文本编辑器的全部。当然,并没有真正做什么,除此之外,在这里仍然有测试和打包步骤,因此仍然有很多时间来发现缺少的必需品。假设你没有注意到提示:在这段代码中 肯定 缺少一些东西。你现在知道缺少的是什么吗?(在 猜谜游戏文章 中被大量的提到。)

测试

你现在可以测试你的应用程序。从终端中启动你所编写的文本编辑器:

$ java ./src/TextEdit.java
error: can’t find main(String[]) method in class: com.example.textedit.TextEdit

它看起来像在代码中没有获得 main 方法。这里有一些方法来修复这个问题:你可以在 TextEdit.java 中创建一个 main 方法,并让它运行一个 TextEdit 类实例,或者你可以创建一个单独的包含 main 方法的文件。两种方法都可以工作,但从大型工程的预期来看,使用后者更为明智,因此,使用单独的文件与其一起工作使之成为一个完整的应用程序的方法是值得使用的。

src 中创建一个 Main.java 文件,并在最喜欢的编辑器中打开:

package com.example.textedit;

public class Main {
  public static void main(String[] args) {
  TextEdit runner = new TextEdit();
  }
}

你可以再次尝试,但是现在有两个相互依赖的文件要运行,因此你必须编译代码。Java 使用 javac 编译器,并且你可以使用 -d 选项来设置目标目录:

$ javac src/*java -d .

这会在你的软件包名称 com/example/textedit 后创建一个准确地模型化的新的目录结构。这个新的类路径包含文件 Main.classTextEdit.class ,这两个文件构成了你的应用程序。你可以使用 java 并通过引用你的 Main 类的位置和 名称(非文件名称)来运行它们:

$ java info/slackermedia/textedit/Main`

你的文本编辑器打开了,你可以在其中输入文字,打开文件,甚至保存你的工作。

 title=

以 Java 软件包的形式分享你的工作

虽然一些程序员似乎看起来认可以各种各样的源文件的形式分发软件包,并鼓励其他人来学习如何运行它,但是,Java 让打包应用程序变得真地很容易,以至其他人可以很容易的运行它。你已经有了必备的大部分结构体,但是你仍然需要一些元数据到一个 Manifest.txt 文件中:

$ echo "Manifest-Version: 1.0" > Manifest.txt

用于打包的 jar 命令,与 tar 命令非常相似,因此很多选项对你来说可能会很熟悉。要创建一个 JAR 文件:

$ jar cvfme TextEdit.jar
Manifest.txt
com.example.textedit.Main
com/example/textedit/*.class

根据命令的语法,你可以推测出它会创建一个新的名称为 TextEdit.jar 的 JAR 文件,它所需要的清单数据位于 Manifest.txt 中。它的主类被定义为软件包名称的一个扩展,并且类自身是 com/example/textedit/Main.class

你可以查看 JAR 文件的内容:

$ jar tvf TextEdit.jar
0 Wed Nov 25 META-INF/
105 Wed Nov 25 META-INF/MANIFEST.MF
338 Wed Nov 25 com/example/textedit/textedit/Main.class
4373 Wed Nov 25 com/example/textedit/textedit/TextEdit.class

如果你想看看你的元数据是如何被集成到 MANIFEST.MF 文件中的,你甚至可以使用 xvf 选项来提取它。

使用 java 命令来运行你的 JAR 文件:

$ java -jar TextEdit.jar

你甚至可以 创建一个桌面文件 ,这样,在单击应用程序菜单中的图标时,应用程序就会启动。

改进它

在当前状态下,这是一个非常基本的文本编辑器,最适合做快速笔记或简短自述文档。一些改进(比如添加垂直滚动条)只要稍加研究就能快速简单地完成,而另一些改进(比如实现一个广泛的偏好系统)则需要真正的工作。

但如果你一直在想学一种新的语言,这可能是一个完美的自我学习实用工程。创建一个文本编辑器,如你所见,它在代码方面并不难对付,它在一定范围是可控的。如果你经常使用文本编辑器,那么编写你自己的文本编辑器可能会使你满意和乐趣。因此打开你最喜欢的文本编辑器(你写的那个),开始添加功能吧!


via: https://opensource.com/article/20/12/write-your-own-text-editor

作者:Seth Kenlon 选题:lujun9972 译者:robsean 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

 title=

ONLYOFFICE 是根据 GNU AGPL v.3 许可证条款分发的开源协作办公套件。它包含三个用于文本文档、电子表格和演示文稿的编辑器,并具有以下功能:

  • 查看,编辑和协同编辑 .docx.xlsx.pptx 文件。OOXML 作为一种核心格式,可确保与 Microsoft Word、Excel 和 PowerPoint 文件的高度兼容性。
  • 通过内部转换为 OOXML,编辑其他流行格式(.odt.rtf.txt.html.ods.csv.odp)。
  • 熟悉的选项卡式界面。
  • 协作工具:两种协同编辑模式(快速和严谨),跟踪更改,评论和集成聊天。
  • 灵活的访问权限管理:完全访问权限、只读、审阅、表单填写和评论。
  • 使用 API 构建附加组件。
  • 250 种可用语言和象形字母表。

通过 API,开发人员可以将 ONLYOFFICE 编辑器集成到网站和利用程序设计语言编写的应用程序中,并能配置和管理编辑器。

要集成 ONLYOFFICE 编辑器,我们需要一个集成应用程序来连接编辑器(ONLYOFFICE 文档服务器)和服务。 要在你的界面中使用编辑器,因该授予 ONLYOFFICE 以下权限:

  • 添加并执行自定义代码。
  • 用于下载和保存文件的匿名访问权限。这意味着编辑器仅与服务器端的服务通信,而不包括客户端的任何用户授权数据(浏览器 cookies)。
  • 在用户界面添加新按钮(例如,“在 ONLYOFFICE 中打开”、“在 ONLYOFFICE 中编辑”)。
  • 开启一个新页面,ONLYOFFICE 可以在其中执行脚本以添加编辑器。
  • 能够指定文档服务器连接设置。

流行的协作解决方案的成功集成案例有很多,如 Nextcloud、ownCloud、Alfresco、Confluence 和 SharePoint,都是通过 ONLYOFFICE 提供的官方即用型连接器实现的。

实际的集成案例之一是 ONLYOFFICE 编辑器与以 C# 编写的开源协作平台的集成。该平台具有文档和项目管理、CRM、电子邮件聚合器、日历、用户数据库、博客、论坛、调查、Wiki 和即时通讯程序的功能。

将在线编辑器与 CRM 和项目模块集成,你可以:

  • 文档关联到 CRM 时机和容器、项目任务和讨论,甚至创建一个单独的文件夹,其中包含与项目相关的文档、电子表格和演示文稿。
  • 直接在 CRM 或项目模块中创建新的文档、工作表和演示文稿。
  • 打开和编辑关联的文档,或者下载和删除。
  • 将联系人从 CSV 文件批量导入到 CRM 中,并将客户数据库导出为 CSV 文件。

在“邮件”模块中,你可以关联存储在“文档模块”中的文件,或者将指向所需文档的链接插入到邮件正文中。 当 ONLYOFFICE 用户收到带有附件的文档的消息时,他们可以:下载附件、在浏览器中查看文件、打开文件进行编辑或将其保存到“文档模块”。 如上所述,如果格式不同于 OOXML ,则文件将自动转换为 .docx.xlsx.pptx,并且其副本也将以原始格式保存。

在本文中,你将看到 ONLYOFFICE 与最流行的编程语言之一的 Python 编写的文档管理系统的集成过程。 以下步骤将向你展示如何创建所有必要的部分,以使在 DMS( 文档管理系统 Document Management System )界面内的文档中可以进行协同工作成为可能:查看、编辑、协同编辑、保存文件和用户访问管理,并可以作为服务的示例集成到 Python 应用程序中。

1、前置需求

首先,创建集成过程的关键组件:ONLYOFFICE 文档服务器 和用 Python 编写的文件管理系统。

1.1、ONLYOFFICE 文档服务器

要安装 ONLYOFFICE 文档服务器,你可以从多个安装选项中进行选择:编译 GitHub 上可用的源代码,使用 .deb.rpm 软件包亦或 Docker 镜像。

我们推荐使用下面这条命令利用 Docker 映像安装文档服务器和所有必需的依赖。请注意,选择此方法,你需要安装最新的 Docker 版本。

docker run -itd -p 80:80 onlyoffice/documentserver-de

1.2、利用 Python 开发 DMS

如果已经拥有一个,请检查它是否满足以下条件:

  • 包含需要打开以查看/编辑的保留文件
  • 允许下载文件

对于该应用程序,我们将使用 Bottle 框架。我们将使用以下命令将其安装在工作目录中:

pip install bottle

然后我们创建应用程序代码 main.py 和模板 index.tpl

我们将以下代码添加到 main.py 文件中:

from bottle import route, run, template, get, static_file # connecting the framework and the necessary components
@route('/') # setting up routing for requests for /
def index():
    return template('index.tpl') # showing template in response to request

run(host="localhost", port=8080) # running the application on port 8080

一旦我们运行该应用程序,点击 http://localhost:8080 就会在浏览器上呈现一个空白页面 。 为了使文档服务器能够创建新文档,添加默认文件并在模板中生成其名称列表,我们应该创建一个文件夹 files 并将3种类型文件(.docx.xlsx.pptx)放入其中。

要读取这些文件的名称,我们使用 listdir 组件(模块):

from os import listdir

现在让我们为文件夹中的所有文件名创建一个变量:

sample_files = [f for f in listdir('files')]

要在模板中使用此变量,我们需要通过 template 方法传递它:

def index():
    return template('index.tpl', sample_files=sample_files)

这是模板中的这个变量:

% for file in sample_files:
  <div>
    <span>{{file}}</span>
  </div>
% end

我们重新启动应用程序以查看页面上的文件名列表。

使这些文件可用于所有应用程序用户的方法如下:

@get("/files/<filepath:re:.*\.*>")
def show_sample_files(filepath):
    return static_file(filepath, root="files")

2、查看文档

所有组件准备就绪后,让我们添加函数以使编辑者可以利用应用接口操作。

第一个选项使用户可以打开和查看文档。连接模板中的文档编辑器 API :

<script type="text/javascript" src="editor_url/web-apps/apps/api/documents/api.js"></script>

editor_url 是文档编辑器的链接接口。

打开每个文件以供查看的按钮:

<button onclick="view('files/{{file}}')">view</button>

现在我们需要添加带有 iddiv 标签,打开文档编辑器:

<div id="editor"></div>

要打开编辑器,必须调用调用一个函数:

<script>
function view(filename) {
    if (/docx$/.exec(filename)) {
        filetype = "text"
    }
    if (/xlsx$/.exec(filename)) {
        filetype = "spreadsheet"
    }
    if (/pptx$/.exec(filename)) {
        filetype = "presentation",
        title: filename
    }
​
    new DocsAPI.DocEditor("editor",
        {
            documentType: filetype,
            document: {
                url: "host_url" + '/' + filename,
                title: filename
            },
            editorConfig: {mode: 'view'}
        });
  }
</script>

DocEditor 函数有两个参数:将在其中打开编辑器的元素 id 和带有编辑器设置的 JSON。 在此示例中,使用了以下必需参数:

  • documentType 由其格式标识(.docx.xlsx.pptx 用于相应的文本、电子表格和演示文稿)
  • document.url 是你要打开的文件链接。
  • editorConfig.mode

我们还可以添加将在编辑器中显示的 title

接下来,我们可以在 Python 应用程序中查看文档。

3、编辑文档

首先,添加 “Edit”(编辑)按钮:

<button onclick="edit('files/{{file}}')">edit</button>

然后创建一个新功能,打开文件进行编辑。类似于查看功能。

现在创建 3 个函数:

<script>
    var editor;
    function view(filename) {
        if (editor) {
            editor.destroyEditor()
        }
        editor = new DocsAPI.DocEditor("editor",
            {
                documentType: get_file_type(filename),
                document: {
                    url: "host_url" + '/' + filename,
                    title: filename
                },
                editorConfig: {mode: 'view'}
            });
    }

    function edit(filename) {
        if (editor) {
            editor.destroyEditor()
        }
        editor = new DocsAPI.DocEditor("editor",
            {
                documentType: get_file_type(filename),
                document: {
                    url: "host_url" + '/' + filename,
                    title: filename
                }
            });
    }

    function get_file_type(filename) {
        if (/docx$/.exec(filename)) {
            return "text"
        }
        if (/xlsx$/.exec(filename)) {
            return "spreadsheet"
        }
        if (/pptx$/.exec(filename)) {
            return "presentation"
        }
    }
</script>

destroyEditor 被调用以关闭一个打开的编辑器。

你可能会注意到,edit() 函数中缺少 editorConfig 参数,因为默认情况下它的值是:{"mode":"edit"}

现在,我们拥有了打开文档以在 Python 应用程序中进行协同编辑的所有功能。

4、如何在 Python 应用中利用 ONLYOFFICE 协同编辑文档

通过在编辑器中设置对同一文档使用相同的 document.key 来实现协同编辑。 如果没有此键值,则每次打开文件时,编辑器都会创建编辑会话。

为每个文档设置唯一键,以使用户连接到同一编辑会话时进行协同编辑。 密钥格式应为以下格式:filename +"_key"。下一步是将其添加到当前文档的所有配置中。

document: {
    url: "host_url" + '/' + filepath,
    title: filename,
    key: filename + '_key'
},

5、如何在 Python 应用中利用 ONLYOFFICE 保存文档

每次我们更改并保存文件时,ONLYOFFICE 都会存储其所有版本。 让我们仔细看看它是如何工作的。 关闭编辑器后,文档服务器将构建要保存的文件版本并将请求发送到 callbackUrl 地址。 该请求包含 document.key和指向刚刚构建的文件的链接。

document.key 用于查找文件的旧版本并将其替换为新版本。 由于这里没有任何数据库,因此仅使用 callbackUrl 发送文件名。

editorConfig.callbackUrl 的设置中指定 callbackUrl 参数并将其添加到 edit() 方法中:

 function edit(filename) {
        const filepath = 'files/' + filename;
        if (editor) {
            editor.destroyEditor()
        }
        editor = new DocsAPI.DocEditor("editor",
            {
                documentType: get_file_type(filepath),
                document: {
                    url: "host_url" + '/' + filepath,
                    title: filename, 
                    key: filename + '_key'
                }
                ,
                editorConfig: {
                    mode: 'edit',
                    callbackUrl: "host_url" + '/callback' + '&amp;filename=' + filename  // add file name as a request parameter
                }
            });
    }

编写一种方法,在获取到 POST 请求发送到 /callback 地址后将保存文件:

@post("/callback") # processing post requests for /callback
def callback():
    if request.json['status'] == 2:
        file = requests.get(request.json['url']).content
        with open('files/' + request.query['filename'], 'wb') as f:
            f.write(file)
    return "{\"error\":0}"
​

# status 2 是已生成的文件,当我们关闭编辑器时,新版本的文件将保存到存储器中。

6、管理用户

如果应用中有用户,并且你需要查看谁在编辑文档,请在编辑器的配置中输入其标识符(idname)。

在界面中添加选择用户的功能:

<select id="user_selector" onchange="pick_user()">
    <option value="1" selected="selected">JD</option>
    <option value="2">Turk</option>
    <option value="3">Elliot</option>
    <option value="4">Carla</option>
</select>

如果在标记 <script> 的开头添加对函数 pick_user() 的调用,负责初始化函数自身 idname 变量。

function pick_user() {
    const user_selector = document.getElementById("user_selector");
    this.current_user_name = user_selector.options[user_selector.selectedIndex].text;
    this.current_user_id = user_selector.options[user_selector.selectedIndex].value;
}

使用 editorConfig.user.ideditorConfig.user.name 来配置用户设置。将这些参数添加到文件编辑函数中的编辑器配置中。

function edit(filename) {
    const filepath = 'files/' + filename;
    if (editor) {
        editor.destroyEditor()
    }
    editor = new DocsAPI.DocEditor("editor",
        {
            documentType: get_file_type(filepath),
            document: {
                url: "host_url" + '/' + filepath,
                title: filename
            },
            editorConfig: {
                mode: 'edit',
                callbackUrl: "host_url" + '/callback' + '?filename=' + filename,
                user: {
                    id: this.current_user_id,
                    name: this.current_user_name
                }
            }
        });
}

使用这种方法,你可以将 ONLYOFFICE 编辑器集成到用 Python 编写的应用程序中,并获得用于在文档上进行协同工作的所有必要工具。有关更多集成示例(Java、Node.js、PHP、Ruby),请参考官方的 API 文档


via: https://opensourceforu.com/2019/09/integrate-online-documents-editors-into-a-python-web-app-using-onlyoffice/

作者:Aashima Sharma 选题:lujun9972 译者:stevenzdg988 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

对于类 Unix 用户来说,Linux 笔记本是不错的选择,但它经常会耗尽电池。我试过很多 Linux 操作系统,但没有像 Windows 那样电池寿命长。

充电时间长了会对电池造成损害,所以在电池 100% 充满时要拔掉电源线。电池充电或放电时没有默认的应用程序来通知,需要安装第三方应用来通知你。

为此,我通常会安装 Battery Monitor,但它已经被废弃,所以我创建了一个 shell 脚本来获取通知。

笔记本电池充放电状态可以通过以下两个命令来识别。

使用 acpi 命令。

$ acpi -b
Battery 0: Discharging, 71%, 00:58:39 remaining

使用 upower 命令。

$ upower -i /org/freedesktop/UPower/devices/battery_BAT0 | grep -w 'state|percentage' | awk '{print $2}'
discharging
64%

方法 1:当电池电量高于 95% 或低于 20% 时,用 Shell 脚本发送警报

这个脚本在启动时在后台运行,每分钟检查一次电池状态,然后在电池电量超过 95% 或放电时电量低于 20% 时发送通知。

警报会直到你的电池电量超过 20% 或低于 95% 时才会停止。

$ sudo vi /opt/scripts/battery-status.sh
#!/bin/bash
while true
do
  battery_level=`acpi -b | grep -P -o '[0-9]+(?=%)'`
   if [ $battery_level -ge 95 ]; then
      notify-send "Battery Full" "Level: ${battery_level}%"
      paplay /usr/share/sounds/freedesktop/stereo/suspend-error.oga
    elif [ $battery_level -le 20 ]; then
      notify-send --urgency=CRITICAL "Battery Low" "Level: ${battery_level}%"
      paplay /usr/share/sounds/freedesktop/stereo/suspend-error.oga
  fi
 sleep 60
done

脚本完成后,设置可执行权限:

$ sudo chmod +x /opt/scripts/battery-status.sh

最后,将该脚本添加到用户配置文件的底部。对于全局范围来说,你需要在 /etc/profile 文件中添加该脚本。

$ vi /home/magi/.profile

/opt/scripts/battery-status.sh &

重启你的 Linux 系统来检查这点。

$ sudo reboot

方法 2:当电池充电(高于 95%)或放电(低于 20%)时发送通知的 Shell 脚本

这个脚本与上面的脚本类似,但它是由交流适配器负责。

如果你插上了交流适配器,而且电池的电量超过 95%,它就会发出一个带有声音的通知,但是这个通知不会停止,直到你拔掉交流适配器。

如果你拔掉交流适配器,你将永远不会再看到通知,直到你的电池电量下降到 20%。

$ sudo vi /opt/scripts/battery-status-1.sh
#!/bin/bash
   while true
    do
       export DISPLAY=:0.0
       battery_level=`acpi -b | grep -P -o '[0-9]+(?=%)'`
       if on_ac_power; then
           if [ $battery_level -ge 95 ]; then
              notify-send "Battery Full" "Level: ${battery_level}% "
              paplay /usr/share/sounds/freedesktop/stereo/suspend-error.oga
           fi
       else
           if [ $battery_level -le 20 ]; then
              notify-send --urgency=CRITICAL "Battery Low" "Level: ${battery_level}%"
              paplay /usr/share/sounds/freedesktop/stereo/suspend-error.oga
           fi
       fi
     sleep 60
done

脚本完成后,设置执行权限:

$ sudo chmod +x /opt/scripts/battery-status-1.sh

最后将脚本添加到用户配置文件的底部。对于全局范围来说,你需要在 /etc/profile 文件中添加该脚本。

$ vi /home/magi/.profile

/opt/scripts/battery-status-1.sh &

重启系统来检查:

$ sudo reboot

参考: stackexchange


via: https://www.2daygeek.com/linux-low-full-charge-discharge-battery-notification/

作者:Magesh Maruthamuthu 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

ElementaryOS 提供了一个快速、轻量、高效的桌面,让你在新的一年里保持工作效率。

在前几年,这个年度系列报道了各个应用程序。今年,我们将在 2021 年寻求帮助的策略之外,还将关注一站式解决方案。欢迎来到 2021 年 21 天生产力的第一天。

当寻求提高生产率的工具时,很容易将几乎能用但不能完全很好地发挥作用的应用集合在一起。在过去的几年里,我们已经谈到了单个的电子邮件应用、日历应用、记事本应用等等。不过,总会有些麻烦。要么需要自定义脚本,要么需要复杂的导出/导入步骤才能使一个工具工作。

ElementaryOS 是一个完整的桌面,具有美观、实用、高效的环境。

ElementaryOS 桌面 (Kevin Sonney, CC BY-SA 4.0

ElementaryOS 是一个基于流行的 Ubuntu Linux 发行版的“按需付费”开源项目。对于过去安装过 Ubuntu 的人来说,初始设置和安装会非常熟悉。然而,一旦登录,体验就会很不一样。

ElementaryOS 使用 Gala 窗口管理器和 Pantheon shell。这两个都是专门为 Elementary 开发的。安装后,桌面非常精简,它只提供了少量的轻量级应用。这些应用包括 Web 浏览器、终端、邮件客户端和日历客户端。它还有一个应用中心,允许你安装 Elementary 团队策划的免费和商业应用。

ElementaryOS 的邮件和日历应用(Kevin Sonney, CC BY-SA 4.0

邮件日历这两个应用看起来很熟悉,因为这两个应用已经被其他发行版使用了一段时间。邮件是作为 Geary 的复刻分支开始的,而日历在其他地方则被称为 Maya。两者的设置非常简单。两款应用默认仅使用用户名/密码认证,所以需要双因素认证的用户需要一些额外的步骤。两者的界面都异常轻巧快速。

应用中心(Kevin Sonney,CC BY-SA 4.0

ElementaryOS 默认不包含待办事项或记事本应用。这时,应用中心就可以发挥作用了。在应用中心中,有大量的应用可以填补空白。其中有两款应用真的很出色。第一个是 Planner,一款简洁、轻量级的待办事项管理器。它支持多个列表、计划和重复性任务、项目和子项目。它还可以与流行的在线应用 Todoist 同步,但这不是必需的。

应用中心的第二款应用是 Notes-Up,这是一款使用 Markdown 写富文本格式的笔记应用。它允许用户在多个笔记本中创建多个笔记,并且有“查看”和“编辑”选项,这样你就可以预览最终文档的样子。同样,这款应用快速、轻量而且非常简约,与 ElementaryOS 的整体外观和感觉保持一致。

Planner 和 Notes-up (Kevin Sonney,CC BY-SA 4.0

如果你不喜欢默认应用,Elementary 基于 Ubuntu LTS,因此如果你需要使用其他应用,整个 Ubuntu 应用生态系统都可以使用。不过总的来说,ElementaryOS 默认提供了一个快速、轻量、高效的桌面,让你在新的一年里保持高效。


via: https://opensource.com/article/21/1/elementary-linux

作者:Kevin Sonney 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出