以docker的方式运行composer时报sh: git: not found

操作系统:ubuntu20

环境:https://github.com/yeszao/dnmp

在宿主机本地安装的jenkins,在jenkins中设置job,composer install,截取部分输出如下:

Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Package operations: 8 installs, 0 updates, 0 removals
  - Installing sebastian/code-unit-reverse-lookup (2.0.2): Downloading (connecting...)Downloading (100%)             Failed to download sebastian/code-unit-reverse-lookup from dist: /tmp/composer/cache/files/sebastian/code-unit-reverse-lookup does not exist and could not be created.
    Now trying to download from source
  - Installing sebastian/code-unit-reverse-lookup (2.0.2): Cloning ee51f9bb0c

                                                                                                                                                          
  [RuntimeException]                                                                                                                                      
  Failed to clone https://github.com/sebastianbergmann/code-unit-reverse-lookup.git, git was not found, check that it is installed and in your PATH env.  
                                                                                                                                                          
  sh: git: not found                                                                                                                                      
                                                                                                                                                          

install [--prefer-source] [--prefer-dist] [--dry-run] [--dev] [--no-dev] [--no-custom-installers] [--no-autoloader] [--no-scripts] [--no-progress] [--no-suggest] [-v|vv|vvv|--verbose] [-o|--optimize-autoloader] [-a|--classmap-authoritative] [--apcu-autoloader] [--ignore-platform-reqs] [--] [<packages>]...

skipping non-regular file "vendor/bin/carbon"
skipping non-regular file "vendor/bin/commonmark"
skipping non-regular file "vendor/bin/php-parse"
skipping non-regular file "vendor/bin/psysh"
skipping non-regular file "vendor/bin/var-dump-server"
Finished: SUCCESS

直接在宿主机进到相应的项目目录执行composer install显示:

Cannot create cache directory /tmp/composer/cache/repo/https---repo.packagist.org/, or directory is not writable. Proceeding without cache
Cannot create cache directory /tmp/composer/cache/files/, or directory is not writable. Proceeding without cache

                                                                            
  [Composer\Downloader\TransportException]                                  
  Content-Length mismatch, received 44625 bytes out of the expected 604017  
                                                                            

require [--dev] [--prefer-source] [--prefer-dist] [--fixed] [--no-progress] [--no-suggest] [--no-update] [--no-scripts] [--update-no-dev] [--update-with-dependencies] [--update-with-all-dependencies] [--ignore-platform-reqs] [--prefer-stable] [--prefer-lowest] [--sort-packages] [-o|--optimize-autoloader] [-a|--classmap-authoritative] [--apcu-autoloader] [--] [<packages>]...

这里的composer命令是通过在.bashrc中添加以下命令实现的:

# php7 composer
composer () {
    tty=
    tty -s && tty=--tty
    docker run \
        $tty \
        --interactive \
        --rm \
        --user www-data:www-data \
        --volume ~/dnmp/data/composer:/tmp/composer \
        --volume $(pwd):/app \
        --workdir /app \
        dnmp_php composer "$@"
}

提示找不到git,但显然是存在的,搜索发现可能是权限问题,就给~/dnmp/data/composer,还有/var/lib/jenkins/workspace目录改成777,问题解决。

最近在研究房车

作为工薪阶层,本来是不应该考虑房车的,因为没有多少时间出去,但越是这样,就越是想出去,如果换个角度思考,房车本来就是周末度假的一种方式,那就让周末过的更有质量不也挺好的吗?当然,目前还没有这个预算,就算有了预算也没有资金。

不过这并不阻碍继续研究,除了挣钱这个命题另外考虑,在假定有钱的情况下还需要考虑以下几个问题:

买什么车型更合适,B型还是C型,六座六卧还是六座四卧。

车停靠在什么地方,小区里的临时车位能不能长期停。

最关键的一个问题是,以北京为中心,周末房车自驾到底能去哪些地方,还要考虑周末要错开孩子上培训班的时间。活动半径在100公里到400公里这个范围。

班级文明小天使

前面那一篇有关小学生守则对比的文章其实是受上小学一年级的女儿第一次评选为班级文明小天使的触动而作,班主任老师发来消息,让自己写50字的“事迹”,还提示可以写与同学相处融洽,纪律好,学习认真等。

我第一感觉是被套路了。这些在校的表现应该老师来写啊,我们家长怎么知道。第二感觉是这种评选本身是否应该存在。当然,不写是不行的,所以就从细节入手吧,看看写的角度怎么着能有点尊严。所以才有了一个小小的调研,遗憾的是时间有限,并有找到这些材料的真正来源,网上流传很广,但不知道国外的出自哪个机构,总之,我不相信他们的版本是出自政府的教育部门。

最终,我们写就的版本是:

准时上学、认真听课、作业全优;分加餐、收作业,积极主动不懒惰;尊师长、爱同学,校内校外朋友多。

基本原则是尽量不写太空洞的话,反映具体事实,有一定的递进层次,而且能反映孩子的主要性格特点。

对于总结出来的一些原则,以后慢慢在讲睡前故事的时候渗透吧。

英日美法中各国小学生守则的对比分析

资料来源:https://www.sohu.com/a/416864708_100031913

资料原文就不照搬了,请点开链接查看。

先看分析结果,上面的图片可以看出各国的侧重点。具体内容就不展开了。

下图是打分的明细,按六个方向打分,总体上每个打分点按10分计,偏弱一点的打5分,交叉的可以同时打分,这样未必规范,也未考虑各国的总分均衡。只是单纯对比下字面的偏重。

房价

2017年在衡水滨湖新区买的房子,为了回老家有个住的地方,7500一平米。现在大概还是这个价位,但是滨湖新区的区域均价在8300左右了。滨湖新区即将开建高铁南站,也许算是一个利好,目前的局势不知道会如何进行下去,如果像恒大那种“死给你看”还有市场的话,可能还能挺几年的时间。只是真的不知道什么时候会崩盘成某些地方那样。

北京的房子是2016年买的,418万,最近邻居卖了,大概在560左右。这几年交了40万利息,溢价在100万上下。

备案25天

尽管网站备案的审核时间是25天这个周期已经是惯例了,而且最近发现注销备案时那个不知道从那里重置的备案密码可以随便填了,但是,我还是觉得这个时间有点荒唐。

6~25个工作日,确实有点太长了,不知道需要做多少调查工作,为什么阿里云的审核基本上就在几个小时以内呢?

自制热敏打印机连接器始末(8)一些基本概念

其实之前参考过这篇文章

https://www.printnode.com/en/docs/what-is-raw-printing

但是他们提供的api没有命令式的,只能打文件,现在回头来看,打印机确实可以这么连接,直接安装为raw的方式就可以用程序打印了,并不需要找驱动。

当然,为了简化cups的操作,对普通用户来说,提供一个tsc的驱动在传统的打印机界面上安装会更简单一些。

在cups中添加的raw打印机只能在cups中可见,打印机与扫描仪管理中是看不见的,当然,node-printer中可以调用到这个打印机。

梳理一下基本概念:

标签打印机:重点当然在标签,每次打印一小截,标签一般是固定大小,指令如TSPL

票据打印机:重点当然是票据,按需打印长度,然后撕掉。指令如EOP。

面单打印机:快递单那种,应该是跟标签打印机差不多,只不过更大。

其实对于打印机厂商来说,很多都已经兼容多种指令了,当然不包括得力这种OEM还不提供开发文档的。

要做一个跨平台的连接器,需要满足几个条件:

(1)能够构建跨平台的发布,所以范围就锁定在electron、xamarin这样的方案上,js和c#虽然都熟悉,但最近用的多的还是js,所以优先选electron,但是其实对node不够熟悉,所以造成了上一篇关于buffer类型的困惑。

(2)搞清楚打印机在不同的操作系统如何连接,目前还没尝试usb直驱这种,在mac上还是通过cups来连接,windows上都有相应的驱动,可以不单独讨论。

(3)指令集兼容性,目前只尝试了TSPL这一种,后续还需要其他的ZPL之类的测试一下,还需要在各种指令之间转换,方便原来用某个指令集编写的程序直接对接。

(4)接入方式的兼容性,至少应该支持socket和http。

(5)统一的api,尤其是友好的RestFul模式的api,便于开发对接。

自制热敏打印机连接器始末(7)指令如何编码,尤其是汉字的编码

接下来就想为什么汉字是乱码呢?是command.setText(50, 100, “TSS24.BF2”, 1, 1, “一二三”);里面的汉字需要转码吗?

对照jpPrinter.addCommand里面把原来的转码去掉了,如果在command.setText(50, 100, “TSS24.BF2”, 1, 1, “一二三”);中把汉字转成unico呢,试了试也不行。

把jpPrinter.addCommand恢复回去,

jpPrinter.addCommand = function(content) {
      // 将指令转成数组装起;
      var code = new encode.TextEncoder("gb18030", {
        NONSTANDARD_allowLegacyEncoding: true,
      }).encode(content);
      for (var i = 0; i < code.length; ++i) {
        command.push(code[i]);
      }
      // command = command + content;
    };

还是会报错,throw new TypeError(‘first argument must be a string or Buffer’);

然后仔细一看,原来data复制不止是string类型,还可以是buffer类型。

那就接着从BluetoothPrinter往这里扒,因为不是蓝牙,不受每次传输的长度限制,所以把分段传输的逻辑去掉。

var data = Array.from(uint8Buf);
  var buffer = new ArrayBuffer(data.length);
  
  var dataView = new DataView(buffer);
  for (var i = 0; i < data.length; ++i) {
    dataView.setUint8(i, data[i]);
  }
  console.log(
    "data type is: " + typeof data + ", is buffer: " + Buffer.isBuffer(data)
  );

但是,还是报同样地错误。

然后发现Buffer.isBuffer(data)是false,为什么类型不对呢?

于是搜到了这里http://nodejs.cn/api/buffer.html#buffer_static_method_buffer_from_arraybuffer_byteoffset_length

是nodejs里面对Buffer有不同于js的类型定义。

于是改成:

var uint8Buf = command.getData();
  var buffer=Buffer.from(uint8Buf);
  console.log(
    "buffer type is: " + typeof buffer + ", is buffer: " + Buffer.isBuffer(buffer)
  );
  var jobid = "";
  printer.printDirect({
    data: buffer, // or simple String: "some text"
    printer: "Deli_DL_888B_NEW_", // printer name, if missing then will print to default printer
    type: "RAW", // type: RAW, TEXT, PDF, JPEG, COMMAND.. depends on platform
    success: function(jobID) {
      console.log("sent to printer with ID: " + jobID);
      jobid = jobID;
    },
    error: function(err) {
      console.log(err);
    },
  });

打印成功。

自制热敏打印机连接器始末(6)验证指令可以驱动打印机输出但有乱码

后来我找到了https://github.com/qihang666/BluetoothPrinter这个项目,人家用蓝牙直接连打印机,比如我手头的DL-888AW就有蓝牙,我用usb为什么就不行呢,所以我就着手将这个项目中的代码拿过来。

尽管他里面的打印机指令集叫jprinter,但指令集实际上是TSPL,所以理论上应该可以复用。

拿过来的部分是https://github.com/qihang666/BluetoothPrinter/tree/master/components/gprint,

考虑到https://github.com/tojocky/node-printer/blob/master/examples/print_raw.js这里面提示的是data部分需要string类型,所以,我把tsc.js里面的command改成了字符串类型,把

jpPrinter.addCommand = function(content) {
      // 将指令转成数组装起;
      var code = new encode.TextEncoder("gb18030", {
        NONSTANDARD_allowLegacyEncoding: true,
      }).encode(content);
      for (var i = 0; i < code.length; ++i) {
        command.push(code[i]);
      }
    };

改成了

jpPrinter.addCommand = function(content) {
       command = command + content;
    };

然后打印的时候:

var command = tsc.jpPrinter.createNew();
  console.log(command);
  command.setSize(60, 40);
  command.setGap(2);
  command.setCls();
  command.setText(50, 10, "2", 1, 1, "Hello");
  command.setText(50, 100, "TSS24.BF2", 1, 1, "一二三");
  // command.setQR(50, 50, "L", 5, "A", "977767937@qq.com");
  command.setPagePrint();

  var data=command.getData();
  var jobid = "";
  printer.printDirect({
    data: data, // or simple String: "some text"
    printer: "Deli_DL_888B_NEW_", // printer name, if missing then will print to default printer
    type: "RAW", // type: RAW, TEXT, PDF, JPEG, COMMAND.. depends on platform
    success: function(jobID) {
      console.log("sent to printer with ID: " + jobID);
      jobid = jobID;
    },
    error: function(err) {
      console.log(err);
    },
  });

惊喜出现了,打印机工作了,但是汉字是乱码。