2022年9月

英伟达 CEO 说“摩尔定律已死”

黄仁勋说,“以同样的成本提供两倍的性能,或者以同样的性能一半的成本,每一年半翻番的摩尔定律,已经结束,它已经完全结束了。”他认为,“计算不是一个芯片问题,而是一个软件和芯片问题”,因而,英伟达为其芯片开发了强大的软件生态系统,这让一些分析师开始将英伟达视为一家迅速崛起的软件公司。

消息来源:Market Watch
老王点评:虽然摩尔定律已经被宣布死亡几次了,但是从现在的半导体技术发展来看,这次可能真的是死了。

CFTC 对去中心化自治组织提起诉讼

美国商品期货交易委员会(CFTC)周四晚些时候公布了对 bZx 协议的开发者的 25 万美元罚款和和解。bZx 是一个用于去中心化借贷的协议。2020 年,bZx 协议因为代码漏洞导致损失了数十万美元的加密货币。同时,CFTC 也对 Ooki DAO 提起诉讼,Ooki DAO 是一个去中心化自治组织,在 2021 年被用来治理该协议。CFTC 在一份法庭文件中说:“DAO 不能免于执法,也不能不受惩罚地违反法律。”这是 CFTC 首次起诉一个去中心化自治组织,也包括治理代币的持有人。

消息来源:The Block
老王点评:可能很多人会有错觉,加密货币是匿名的,DAO 是法不责众的。

调查显示老板们认为员工在家干活少

微软的一项新调查显示,老板和员工对在家工作时的生产力有根本性的分歧。87% 的员工认为他们在家工作的效率和在办公室一样高,甚至更高,但 80% 的经理不同意此看法。这项调查询问了 11 个国家的 2 万多名员工。在 LinkedIn 上通常有大约 1400 或 1500 万个职位,在疫情之前,其中约有 2% 涉及远程工作。几个月前,这一比例为 20%,而本月已降至 15%。

消息来源:BBC
老王点评:反正我在家就不想干活。

开源库 GObject 和 libsoup 做了很多工作,因此你可以专注于使用 C 语言开发神奇的应用。

GLib 对象系统 Object System (GObject)是一个为 C 语言提供灵活且可扩展的面向对象框架的库。在这篇文章中,我将使用该库的 2.4 版本进行演示。

GObject 库继承了 ANSI C 标准,拥有一些常见的数据类型,例如:

  • gchar:字符型
  • guchar:无符号字符型
  • gunichar:32 位定宽 Unicode 字符型
  • gboolean:布尔型
  • gint8gint16gint32gint64:有符号 8、16、32 和 64 位整数
  • guint8guint16guint32guint64:无符号 8、16、32 和 64 位整数
  • gfloat:IEEE 754 标准单精度浮点数
  • gdouble:IEEE 754 标准双精度浮点数
  • gpointer:泛指针

函数指针

GObject 库还引入了类和接口的类型和对象体系。之所以可以,是因为 ANSI C 语言可以理解函数指针。

你可以这样做来声明函数指针:

void (*my_callback)(gpointer data);

首先,你需要给变量 my_callback 赋值:

void my_callback_func(gpointer data)
{
  //do something
}

my_callback = my_callback_func;

函数指针 my_callback 可以这样来调用:

gpointer data;
data = g_malloc(512 * sizeof(gint16));
my_callback(data);

对象类

GObject 基类由 2 个结构(GObjectGObjectClass)组成,你可以继承它们以实现你自己的对象。

你需要在结构体中先嵌入 GObjectGObjectClass

struct _MyObject
{
  GObject gobject;
  //your fields
};

struct _MyObjectClass
{
  GObjectClass gobject;
  //your class methods
};

GType my_object_get_type(void);

对象的实现包含了公有成员。GObject 也提供了私有成员的方法。这实际上是 C 源文件中的一个结构,而不是在头文件。该类通常只包含函数指针。

一个接口不能派生自另一个接口,比如:

struct _MyInterface
{
  GInterface ginterface;
  //your interface methods
};

通过调用 g_object_get()g_object_set() 函数来访问属性。若要获取属性,你必须提供特定类型的返回位置。建议先初始化返回位置:

gchar *str

str = NULL;

g_object_get(gobject,
  "my-name", &str,
  NULL);

或者你想要设置属性:

g_object_set(gobject,
  "my-name", "Anderson",
  NULL);

libsoup HTTP 库

libsoup 项目为 GNOME 提供了 HTTP 客服端和服务端使用的库。它使用 GObjects 和 glib 主循环与集成到 GNOME 应用,并且还具有用于命令行的同步 API。

首先,创建一个特定身份验证回调的 libsoup 会话。你也可以使用 cookie。

SoupSession *soup_session;
SoupCookieJar *jar;

soup_session = soup_session_new_with_options(SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_AUTH_BASIC,
  SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_AUTH_DIGEST,
  NULL);

jar = soup_cookie_jar_text_new("cookies.txt",
  FALSE);     

soup_session_add_feature(soup_session, jar);
g_signal_connect(soup_session, "authenticate",
  G_CALLBACK(my_authenticate_callback), NULL);

然后你可以像这样创建一个 HTTP GET 请求:

SoupMessage *msg;
SoupMessageHeaders *response_headers;
SoupMessageBody *response_body;
guint status;
GError *error;

msg = soup_form_request_new("GET",
  "http://127.0.0.1:8080/my-xmlrpc",
  NULL);

status = soup_session_send_message(soup_session,
  msg);

response_headers = NULL;
response_body = NULL;

g_object_get(msg,
  "response-headers", &response_headers,
  "response-body", &response_body,
  NULL);

g_message("status %d", status);
cookie = NULL;
soup_message_headers_iter_init(&iter,
response_headers);

while(soup_message_headers_iter_next(&iter, &name, &value)){    
  g_message("%s: %s", name, value);
}

g_message("%s", response_body->data);
if(status == 200){
  cookie = soup_cookies_from_response(msg);
  while(cookie != NULL){
    char *cookie_name;
    cookie_name = soup_cookie_get_name(cookie->data);
    //parse cookies
    cookie = cookie->next;
  }
}

当网络服务器进行身份认证时,会调用身份认证回调函数。

这是一个函数签名:

#define MY_AUTHENTICATE_LOGIN "my-username"
#define MY_AUTHENTICATE_PASSWORD "my-password"

void my_authenticate_callback(SoupSession *session,
  SoupMessage *msg,
  SoupAuth *auth,
  gboolean retrying,
  gpointer user_data)
{
  g_message("authenticate: ****");
  soup_auth_authenticate(auth,
                         MY_AUTHENTICATE_LOGIN,
                         MY_AUTHENTICATE_PASSWORD);
}

一个 libsoup 服务器

想要基础的 HTTP 身份认证能够运行,你需要指定回调函数和服务器上下文路径。然后再添加一个带有另一个回调的处理程序。

下面这个例子展示了在 8080 端口监听任何 IPv4 地址的消息:

SoupServer *soup_server;
SoupAuthDomain *auth_domain;
GSocket *ip4_socket;
GSocketAddress *ip4_address;
MyObject *my_object;
GError *error;

soup_server = soup_server_new(NULL);
auth_domain = soup_auth_domain_basic_new(SOUP_AUTH_DOMAIN_REALM, "my-realm",
  SOUP_AUTH_DOMAIN_BASIC_AUTH_CALLBACK, my_xmlrpc_server_auth_callback,
  SOUP_AUTH_DOMAIN_BASIC_AUTH_DATA, my_object,
  SOUP_AUTH_DOMAIN_ADD_PATH, "my-xmlrpc",
  NULL);

soup_server_add_auth_domain(soup_server, auth_domain);
soup_server_add_handler(soup_server,
  "my-xmlrpc",
  my_xmlrpc_server_callback,
  my_object,
  NULL);

ip4_socket = g_socket_new(G_SOCKET_FAMILY_IPV4,
  G_SOCKET_TYPE_STREAM,
  G_SOCKET_PROTOCOL_TCP,
  &error);

ip4_address = g_inet_socket_address_new(g_inet_address_new_any(G_SOCKET_FAMILY_IPV4),
  8080);
error = NULL;
g_socket_bind(ip4_socket,
  ip4_address,
  TRUE,
  &error);
error = NULL;
g_socket_listen(ip4_socket, &error);

error = NULL;
soup_server_listen_socket(soup_server,
  ip4_socket, 0, &error);

示例代码中,有两个回调函数。一个处理身份认证,另一个处理对它的请求。

假设你想要网页服务器允许用户名为 my-username 和口令为 my-password 的凭证登录,并且用一个随机且唯一的用户 ID 字符串设置会话 cookie。

gboolean my_xmlrpc_server_auth_callback(SoupAuthDomain *domain,
  SoupMessage *msg,
  const char *username,
  const char *password,
  MyObject *my_object)
{
  if(username == NULL || password == NULL){
    return(FALSE);
  }

  if(!strcmp(username, "my-username") &&
     !strcmp(password, "my-password")){
    SoupCookie *session_cookie;
    GSList *cookie;
    gchar *security_token;
    cookie = NULL;

    security_token = g_uuid_string_random();
    session_cookie = soup_cookie_new("my-srv-security-token",
      security_token,
      "localhost",
      "my-xmlrpc",
      -1);

     cookie = g_slist_prepend(cookie,
       session_cookie);  
     soup_cookies_to_request(cookie,
       msg);
    return(TRUE);
  }
  return(FALSE);
}

对上下文路径 my-xmlrpc 进行处理的函数:

void my_xmlrpc_server_callback(SoupServer *soup_server,
  SoupMessage *msg,
  const char *path,
  GHashTable *query,
  SoupClientContext *client,
  MyObject *my_object)
{
  GSList *cookie;
  cookie = soup_cookies_from_request(msg);
  //check cookies
}

更加强大的 C 语言

希望我的示例展现了 GObject 和 libsoup 项目给 C 语言带来了真正的提升。像这样在字面意义上扩展 C 语言,可以使 C 语言更易于使用。它们已经为你做了许多工作,这样你可以专注于用 C 语言开发简单、直接的应用程序了。


via: https://opensource.com/article/22/5/libsoup-gobject-c

作者:Joël Krähemann 选题:lkxed 译者:Donkey-Hao 校对:wxy

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

RDNA 2 GPU 的 Linux 用户可以使用 AMD 的 AMDVLK GPUOpen 开源 Vulkan 驱动程序。

用于 Radeon RX 6000 GPU 的 AMDVLK GPUOpen 图形驱动程序在过去一周改进了对 64 位光线追踪的支持。这涵盖了支持 RDNA 2 图形的 APU 以及桌面/移动 GPU。所有平台上的所有 AMD Vulkan 驱动程序现在都支持硬件光线追踪,包括 Mesa3D RADV、AMDVLK GPUOpen 和 AMDGPU-PRO。

GPU 光线追踪库(GPURT)的基础是一个 C++ 接口。根据其用法和依赖关系,公共接口被拆分为各种头文件。用户可以在官方的 GitHub 仓库上了解更多信息,它还包括了 RDNA 2 GPURT 的结构细分。最新的 AMDVLK GPUOpen v-2022.Q3.4 信息如下:

更新和新功能:

  • 扩展 Navi2x 的 64 位光线追踪功能。
  • 将 Vulkan 标头升级到版本 1.3.225
  • 游戏性能优化,包括《荣耀战魂》和《奇点灰烬》

已解决的问题:

  • dEQP-VK.api.copy_and_blit.*.resolve_image.whole_copy_before_resolving_transfer.* 新版本 CTS 失败。
  • dEQP-VK.pipeline.creation 缓存控件有一个 CTS 警告。
  • Ubuntu 22.04 上的 Firefox 损坏
  • VulkanInfo 崩溃,管道缓存已停用
  • RX 6800 上的 RGP 测试套件故障

新的改进包括 GPU 光线追踪库(GPURT),它将包括使用 HLSL 之类的着色器在光线追踪中看到的边界体积层次(BVH)的构造和排序处理。这个库将提供一个标准库来改进图形渲染并引入更多的统一性。DirectX 12 DXR 也将与新库一起使用。

对 GPU 光线追踪(GPURT)库的描述为“一个静态库(源代码交付),为支持 DXR(DirectX 12)和 Vulkan® RT API 的 AMD 驱动程序提供与光线追踪相关的功能。” 该公司的平台抽象库用于构建库(PAL)。

用户可参考最新 AMDVLK GPUOpen v-2022.Q3.4 升级的安装说明。用户在更新任何软件、硬件或驱动程序之前应备份所有相关数据,以免丢失重要文件。

为了让最新的 Linux 驱动程序为 AMD、Intel 和 NVIDIA 技术做好准备,已经投入了大量工作,这些技术都是在今年第一季度推出的。


via: https://www.opensourceforu.com/2022/09/amds-open-source-vulkan-graphics-drivers-now-enable-ray-tracing/

作者:Laveesh Kocher 选题:lkxed 译者:littlebirdnest 校对:wxy

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

一些已知的、或鲜为人知的事情 —— 这里有 20 件关于 Linux 内核创造者 Linus Torvalds 的趣事。

Linus Torvalds,Linux 和 Git 的创造者

Linus Benedict Torvalds(林纳斯·本纳第克特·托瓦兹),在 1991 年还是一名攻读硕士的芬兰学生时,他开发了一个类 Unix 操作系统。从那时起,它引发了一场革命:今天,它为大多数 Web 服务器、许多嵌入式设备和 500 强超级计算机 中的每一台提供支持。

我已经写过一些鲜为人知的 关于 Linux 的事实,但这篇文章不是关于 Linux 的,而是关于它的创造者,Linus Torvalds。

通过阅读他的传记《 只是为了好玩 Just for Fun 》,我了解了有关 Torvalds 的许多事情。如果你有兴趣,你也可以 订购一本传记。(这是一个 受益推荐 链接。)

关于 Linus Torvalds 的 20 个有趣事实

你可能已经知道一些关于 Linus 的事情,但是通过阅读这篇文章,你很有可能会了解一些关于他的新趣事。

1、以诺贝尔奖获得者的名字命名

Linus Benedict Torvalds 于 1969 年 12 月 28 日出生于赫尔辛基。他来自一个记者家庭。他的父亲 Nils Torvalds 是芬兰政治家,可能是未来参加选举的总统候选人。

他的名字来自于诺贝尔化学与和平奖的双奖获得者 Linus Pauling 的名字。

2、世界上所有的 Torvalds 都是亲戚

虽然你可能会找到几个名字为 Linus 的人,但你不会找到很多姓 Torvalds 的人 —— 因为“正确”的拼写实际上是 Torvald(没有 s)。他的祖父将名字从 Torvald 改为 Torvalds,并在末尾添加了一个“s”。于是,Torvalds 王朝(如果我可以这么称呼它的话)开始了。

由于这是一个不寻常的姓氏,所以世界上只有不到 30 个 Torvalds,而且他们都是亲戚,这是 Linus Torvalds 在他的传记中说的。

年轻的 Linus Torvalds 和他的记者妹妹 Sara Torvalds

3、他的第一台电脑是 Commodore Vic 20

10 岁时,Linus 开始在他外祖父的 Commodore Vic 20 上使用 BASIC 编写程序。这使他发现自己对计算机和编程的热爱。

4、Linus Torwalds 少尉

尽管他更喜欢花时间在电脑上而不是体育活动上,但他必须参加强制性的军事训练。他的军衔是少尉。

5、因为他没有钱购买 UNIX,他创造了 Linux

1991 年初,出于对 MS-DOSMINIX 不满意,Torvalds 想购买一套 UNIX 系统。对我们来说幸运的是,他没有足够的钱。因此,他决定从头开始制作自己的 UNIX 复制品。

6、Linux 可以被称为 Freax

1991 年 9 月,Linus 发布了 Linux(代表 “Linus's MINIX”)并鼓励他的同好们使用其源代码进行更广泛的分发。

Linus 认为 Linux 这个名字太自负了。他想把它改成 Freax(基于 free、freak 和 MINIX),但他的朋友 Lemmarke 已经在 FTP 服务器上创建了一个名为 Linux 的目录。因此,Linux 的名称才得以沿用下来。(LCTT 译注:这个故事和我听到的不同。)

7、Linux 是他在大学的主要项目

《Linux:一种可移植的操作系统》是他的硕士论文题目。

8、他娶了他的学生

1993 年,他在赫尔辛基大学任教时,给学生们布置了一份写电子邮件的作业。是的,当时撰写电子邮件没那么简单。

一位名叫 Tove Monni 的女学生完成了这项任务,给他发送一封电子邮件,并邀请他出去约会。他接受了,三年后,他们三个女儿中的第一个出生了。

我应该说他开创了网恋的潮流吗?嗯……不!让我们就此打住 :wink:

Linus Torvalds 和他的妻子 Tove Monni Torvalds

9、Linus 有一颗以他的名字命名的小行星

他的名字获得了无数荣誉,包括一颗名为 9793 Torvalds 的小行星。

10、Linus 不得不为 Linux 的商标而战

Linux 是 Linus Torvalds 的注册商标。Torvalds 最初并不关心这个商标,但在 1994 年 8 月,William R. Della Croce, Jr. 注册了 Linux 商标,并开始向 Linux 开发人员索要版税。作为回应,Torvalds 起诉了他,并于 1997 年解决了此案。

11、史蒂夫·乔布斯希望他为苹果公司的 macOS 工作

2000 年,苹果公司的创始人 史蒂夫·乔布斯邀请他为苹果公司的 macOS 工作。Linus 拒绝了这个报酬丰厚的提议,并继续致力于开发 Linux 内核。

12、Linus 还创建了 Git

大多数人都知道 Linus Torvalds 创建 Linux 内核,但他还创建了 Git,这是一个广泛用于全世界的软件开发的版本控制系统。

直到 2005 年,(当时)专有服务 BitKeeper 还用于 Linux 内核的开发。而当 Bitkeeper 关闭其免费服务时,Linus Torvalds 自己创建了 Git,因为其他版本控制系统都不能满足他的需求。

13、如今 Linus 几乎不编程

尽管 Linus 全职从事 Linux 内核工作,但他几乎不再为它编写任何代码。事实上,Linux 内核中的大部分代码都来自世界各地的贡献者。他在内核维护人员的帮助下,确保每个版本发布都能顺利进行。

14、Torvalds 讨厌 C++

Linus Torvalds 极其 不喜欢 C++ 编程语言,并对此直言不讳。他开玩笑说 Linux 内核的编译速度都比 C++ 程序快。

15、即使是 Linus Torvalds 也发现 Linux 难以安装(现在你可以自我感觉良好了)

几年前,Linus 说过 他发现 Debian 难以安装。众所周知,他 在他的主要工作站上使用 Fedora

16、他喜欢水肺潜水

Linus Torvalds 喜欢水肺潜水。他甚至创造了一种供水肺潜水员使用的潜水记录工具 Subsurface。你会惊讶地发现,有时他甚至会在论坛上回答一些普通问题。

穿着潜水装备的 Linus Torvalds

17、满嘴脏话的 Torvalds 改善了他的行为

Torvalds 以在 Linux 内核邮件列表中使用 轻度脏话 而闻名,这遭到了一些业内人士的批评。但是,很难批评他对 “F**k you, NVIDIA” 的玩笑,因为它促使英伟达为 Linux 内核提供了更好的适配。

2018 年,Torvalds 暂时离开了 Linux 内核开发,以改善他的行为。这是在他签署有争议的 Linux 内核开发人员行为准则 之前完成的。

Linus Torvalds 对英伟达的中指:去你的!英伟达

18、他太害羞了,不敢在公共场合讲话

Linus 对公开演讲感到不舒服。他不怎么参加活动。而当他必须参加时,他更喜欢坐下来接受主持人的采访。这是他最喜欢的公开演讲方式。

19、他不是社交媒体爱好者

Google Plus 是他使用过的唯一社交媒体平台。他甚至在空闲时花了一些时间 点评了小组件。Google Plus 现已停用了,因此他没有其他社交媒体帐户。

20、Torvalds 定居在美国

Linus 于 1997 年移居美国,并与他的妻子 Tove 和他们的三个女儿在那里定居。他于 2010 年成为美国公民。目前,作为 Linux 基金会 的成员,他全职从事 Linux 内核工作。

很难说 Linus Torvalds 的净资产是多少,或者 Linus Torvalds 的收入是多少,因为这些信息从未公开过。

Tove 和 Linus Torvalds 和他们的女儿 Patricia、Daniela 和 Celeste

如果你有兴趣了解更多有关 Linus Torvalds 早期生活的信息,我建议你阅读他的传记,书名为 《 只是为了好玩 Just for Fun 》。

免责声明:这里的一些图片来源于互联网,我没有图像的版权,我也不打算用这篇文章侵犯 Torvalds 家族的隐私。


via: https://itsfoss.com/linus-torvalds-facts/

作者:Abhishek Prakash 选题:lkxed 译者:gpchn 校对:wxy

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

微软 Azure CTO 称 C/C++ 应该被废弃

他在 Twitter 发表了个人观点:“是时候停止用 C/C++ 启动任何新项目了,在那些需要非 GC 语言的场景中使用 Rust。为了安全和可靠性,行业应该宣布这些语言被废弃。”这并不是微软第一次倡导将 Rust 作为提高软件安全的一种手段。三年前,微软安全响应中心(MSRC)表示,“我们认为 Rust 代表了目前 C 和 C++ 的最佳替代品。……MSRC 分配了 CVE 编号的安全问题中,大约有 70% 是内存安全问题。这意味着,如果该软件是用 Rust 编写的,这些内存安全问题很可能已经被消除了。”

消息来源:Dev Class
老王点评:Rust 是一个很有希望,但是仍然不够成熟和完善的语言,不过,C/C++ 程序员们可以开始学了。

Mozilla 发布报告指责操作系统与浏览器的锁定

浏览器市场份额已经急剧减少的 Mozilla 最近发布研究报告,整篇报告并未有什么新的证据和观点。在报告中,Mozilla 警告说,“浏览器市场的竞争对于确保创新和消费者的选择至关重要,更广泛地说,保护开放网络的活力,防止商业巨头试图封锁它。”并称,“相比之下,来自独立浏览器的竞争可以帮助推动新的功能,以及在隐私和安全等领域的创新”。

消息来源:Tech Crunch
老王点评:首先,请把 Firefox 做好,而不是指责别人借助优势扩大份额吧。

被忽视 15 年的 Python 漏洞导致 35 万项目陷入风险

早在 2007 年,就已经有安全研究人员披露了一个 Python 的安全风险,并得到了编号 CVE-2007-4559。遗憾的是,它一直没有获得正式的修复补丁。唯一的缓解措施,也只是在更新后的开发者文档中提示了相关风险。今年早些时候,一位安全研究人员在调查另一个安全问题时,再次发现该漏洞可用于代码执行。该漏洞位于 Python tarfile 包中,预估有超过 35 万个存储库易受该漏洞攻击的影响,且其中不乏重要项目,如 GitHub Copilot。

消息来源:Bleeping Computer
老王点评:又一个开源供应链安全漏洞。任何一个不起眼的小漏洞都可能引起大坝崩溃。

使用 Python 中的 scaffoldclick 库,你可以将一个简单的实用程序升级为一个成熟的命令行界面工具。

Python 吉祥物和 Linux 的吉祥物企鹅

在我的职业生涯中,我写过、用过和看到过很多随意的脚本。一些人需要半自动化完成任务,于是它们诞生了。一段时间后,它们变得越来越大。它们在一生中可能转手很多次。我常常希望这些脚本提供更多的命令行工具式的感觉。但是,从一次性脚本到合适的工具,真正提高质量水平有多难呢?事实证明这在 Python 中并不难。

搭建骨架脚本

在本文中,我将从一小段 Python 代码开始。我将把它应用到 scaffold 模块中,并使用 click 库扩展它以接受命令行参数。

#!/usr/bin/python

from glob import glob
from os.path import join, basename
from shutil import move
from datetime import datetime
from os import link, unlink

LATEST = 'latest.txt'
ARCHIVE = '/Users/mark/archive'
INCOMING = '/Users/mark/incoming'
TPATTERN = '%Y-%m-%d'

def transmogrify_filename(fname):
    bname = basename(fname)
    ts = datetime.now().strftime(TPATTERN)
    return '-'.join([ts, bname])

def set_current_latest(file):
    latest = join(ARCHIVE, LATEST)
    try:
        unlink(latest)
    except:
        pass
    link(file, latest)

def rotate_file(source):
    target = join(ARCHIVE, transmogrify_filename(source))
    move(source, target)
    set_current_latest(target)

def rotoscope():
    file_no = 0
    folder = join(INCOMING, '*.txt')
    print(f'Looking in {INCOMING}')
    for file in glob(folder):
        rotate_file(file)
        print(f'Rotated: {file}')
        file_no = file_no + 1
    print(f'Total files rotated: {file_no}')

if __name__ == '__main__':
    print('This is rotoscope 0.4.1. Bleep, bloop.')
    rotoscope()

本文所有没有在这里插入显示的代码示例,你都可以在 https://codeberg.org/ofosos/rotoscope 中找到特定版本的代码。该仓库中的每个提交都描述了本文操作过程中一些有意义的步骤。

这个片段做了几件事:

  • 检查 INCOMING 指定的路径中是否有文本文件
  • 如果存在,则使用当前时间戳创建一个新文件名,并将其移动到 ARCHIVE
  • 删除当前的 ARCHIVE/latest.txt 链接,并创建一个指向刚刚添加文件的新链接

作为一个示例,它很简单,但它会让你理解这个过程。

使用 Pyscaffold 创建应用程序

首先,你需要安装 scaffoldclicktox Python 库

$ python3 -m pip install scaffold click tox

安装 scaffold 后,切换到示例的 rotoscope 项目所在的目录,然后执行以下命令:

$ putup rotoscope -p rotoscope \
    --force --no-skeleton -n rotoscope \
    -d 'Move some files around.' -l GLWT \
    -u http://codeberg.org/ofosos/rotoscope \
    --save-config --pre-commit --markdown

Pyscaffold 会重写我的 README.md,所以从 Git 恢复它:

$ git checkout README.md

Pyscaffold 在文档中说明了如何设置一个完整的示例项目,我不会在这里介绍,你之后可以探索。除此之外,Pyscaffold 还可以在项目中为你提供持续集成(CI)模板:

  • 打包: 你的项目现在启用了 PyPi,所以你可以将其上传到一个仓库并从那里安装它。
  • 文档: 你的项目现在有了一个完整的文档文件夹层次结构,它基于 Sphinx,包括一个 readthedocs.org 构建器。
  • 测试: 你的项目现在可以与 tox 一起使用,测试文件夹包含运行基于 pytest 的测试所需的所有样板文件。
  • 依赖管理: 打包和测试基础结构都需要一种管理依赖关系的方法。setup.cfg 文件解决了这个问题,它包含所有依赖项。
  • 预提交钩子: 包括 Python 源代码格式工具 black 和 Python 风格检查器 flake8。

查看测试文件夹并在项目目录中运行 tox 命令,它会立即输出一个错误:打包基础设施无法找到相关库。

现在创建一个 Git 标记(例如 v0.2),此工具会将其识别为可安装版本。在提交更改之前,浏览一下自动生成的 setup.cfg 并根据需要编辑它。对于此示例,你可以修改 LICENSE 和项目描述,将这些更改添加到 Git 的暂存区,我必须禁用预提交钩子,然后提交它们。否则,我会遇到错误,因为 Python 风格检查器 flake8 会抱怨糟糕的格式。

$ PRE_COMMIT_ALLOW_NO_CONFIG=1 git commit

如果这个脚本有一个入口点,用户可以从命令行调用,那就更好了。现在,你只能通过找 .py 文件并手动执行它来运行。幸运的是,Python 的打包基础设施有一个很好的“罐装”方式,可以轻松地进行配置更改。将以下内容添加到 setup.cfgoptions.entry_points 部分:

console_scripts =
    roto = rotoscope.rotoscope:rotoscope

这个更改会创建一个名为 roto 的 shell 命令,你可以使用它来调用 rotoscope 脚本,使用 pip 安装 rotoscope 后,可以使用 roto 命令。

就是这样,你可以从 Pyscaffold 免费获得所有打包、测试和文档设置。你还获得了一个预提交钩子来保证(大部分情况下)你按照设定规则提交。

CLI 工具化

现在,一些值会硬编码到脚本中,它们作为命令 参数 会更方便。例如,将 INCOMING 常量作为命令行参数会更好。

首先,导入 click 库,使用 Click 提供的命令装饰器对 rotoscope() 方法进行装饰,并添加一个 Click 传递给 rotoscope 函数的参数。Click 提供了一组验证器,因此要向参数添加一个路径验证器。Click 还方便地使用函数的内嵌字符串作为命令行文档的一部分。所以你最终会得到以下方法签名:

@click.command()
@click.argument('incoming', type=click.Path(exists=True))
def rotoscope(incoming):
    """
    Rotoscope 0.4 - Bleep, blooop.
    Simple sample that move files.
    """

主函数会调用 rotoscope(),它现在是一个 Click 命令,不需要传递任何参数。

选项也可以使用 环境变量 自动填充。例如,将 ARCHIVE 常量改为一个选项:

@click.option('archive', '--archive', default='/Users/mark/archive', envvar='ROTO_ARCHIVE', type=click.Path())

使用相同的路径验证器。这一次,让 Click 填充环境变量,如果环境变量没有提供任何内容,则默认为旧常量的值。

Click 可以做更多的事情,它有彩色的控制台输出、提示和子命令,可以让你构建复杂的 CLI 工具。浏览 Click 文档会发现它的更多功能。

现在添加一些测试。

测试

Click 对使用 CLI 运行器 运行端到端测试 提供了一些建议。你可以用它来实现一个完整的测试(在 示例项目 中,测试在 tests 文件夹中。)

测试位于测试类的一个方法中。大多数约定与我在其他 Python 项目中使用的非常接近,但有一些细节,因为 rotoscope 使用 click。在 test 方法中,我创建了一个 CliRunner。测试使用它在一个隔离的文件系统中运行此命令。然后测试在隔离的文件系统中创建 incomingarchive 目录和一个虚拟的 incoming/test.txt 文件,然后它调用 CliRunner,就像你调用命令行应用程序一样。运行完成后,测试会检查隔离的文件系统,并验证 incoming 为空,并且 archive 包含两个文件(最新链接和存档文件)。

from os import listdir, mkdir
from click.testing import CliRunner
from rotoscope.rotoscope import rotoscope

class TestRotoscope:
    def test_roto_good(self, tmp_path):
        runner = CliRunner()

        with runner.isolated_filesystem(temp_dir=tmp_path) as td:
            mkdir("incoming")
            mkdir("archive")
            with open("incoming/test.txt", "w") as f:
                f.write("hello")

            result = runner.invoke(rotoscope, ["incoming", "--archive", "archive"])
            assert result.exit_code == 0

            print(td)
            incoming_f = listdir("incoming")
            archive_f = listdir("archive")
            assert len(incoming_f) == 0
            assert len(archive_f) == 2

要在控制台上执行这些测试,在项目的根目录中运行 tox

在执行测试期间,我在代码中发现了一个错误。当我进行 Click 转换时,rotoscope 只是取消了最新文件的链接,无论它是否存在。测试从一个新的文件系统(不是我的主文件夹)开始,很快就失败了。我可以通过在一个很好的隔离和自动化测试环境中运行来防止这种错误。这将避免很多“它在我的机器上正常工作”的问题。

搭建骨架脚本和模块

本文到此结束,我们可以使用 scaffoldclick 完成一些高级操作。有很多方法可以升级一个普通的 Python 脚本,甚至可以将你的简单实用程序变成成熟的 CLI 工具。


via: https://opensource.com/article/22/7/bootstrap-python-command-line-application

作者:Mark Meyer 选题:lkxed 译者:MjSeven 校对:wxy

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