helloworld Snap例程
来源:互联网 发布:什么是知天命 编辑:程序博客网 时间:2024/06/10 12:30
我们在很多的语言开发中都少不了使用"Hello, the world!"来展示一个开发环境的成功与否,在今天的教程中,我们也毫不例外地利用这个例子来展示snap应用是如何构建的.虽然这个例子很简单,但是在我们进入例程的过程中,我们会慢慢地发现有关snap系统的一些特性,这样可以更好地帮助我们来了解这个系统.如果大家想了解16.04的桌面对snap的支持,请参阅文章"安装snap应用到Ubuntu 16.4桌面系统".
1)环境安装
我们仿照在文章"安装snap应用到Ubuntu 16.4桌面系统"中的"安装"一节进行安装.记得一定要选上"universe"才可以安装成功.
2)从Snap商店中安装hello-world应用
我们可以通过如下的命令在Snap商店中找到这个应用:
$ sudo snap install hello-world
在安装完这个应用后,我们可以在如下的目录中找到关于这个应用的snap.yaml文件.这个文件很类似于一个项目的snapcraft.yaml文件.只是它里面没有什么parts的部分.
liuxg@liuxg:/snap/hello-world/current/meta$ ls gui snap.yaml
snap.yaml
name: hello-worldversion: 6.3architectures: [ all ]summary: The 'hello-world' of snapsdescription: | This is a simple snap example that includes a few interesting binaries to demonstrate snaps and their confinement. * hello-world.env - dump the env of commands run inside app sandbox * hello-world.evil - show how snappy sandboxes binaries * hello-world.sh - enter interactive shell that runs in app sandbox * hello-world - simply output textapps: env: command: bin/env evil: command: bin/evil sh: command: bin/sh hello-world: command: bin/echo
可以看出来它的格式非常接近我们的snapcraft.yaml项目文件.这里文件中指出的env,evil,sh及echo命令,我们可以在如下的目录中找到:
liuxg@liuxg:/snap/hello-world/current/bin$ lsecho env evil sh
liuxg@liuxg:/snap/hello-world/current$ tree -L 3.├── bin│ ├── echo│ ├── env│ ├── evil│ └── sh└── meta ├── gui │ └── icon.png └── snap.yaml
3)创建我们自己的hello-world项目
由于一些原因,我们在网上已经找不到这个项目的源码了.由于这个项目非常简单,我们可以通过我们自己的方法来重建这个项目:我们把上面的snap.yaml进行修改为我们所需要的snapcraft.yaml,并把我们所需要的文件考入到我们需哟啊的目录.这样我们就可以很容易地重构这个项目.这样做的目的是我们想通过修改这个项目来展示一些我们想看到的特性.
对于开发者来说,如果你没有一个现成的snapcraft.yaml文件供你参考的话,你可以直接使用如下的命令来生产一个模版来进行编辑:
$ snapcraft init
snapcraft.yaml
name: my-snap # the name of the snapversion: 0 # the version of the snapsummary: This is my-snap's summary # 79 char long summarydescription: This is my-snap's description # a longer description for the snapconfinement: devmode # use "strict" to enforce system access only via declared interfacesparts: my-part: # Replace with a part name of your liking # Get more information about plugins by running # snapcraft help plugins # and more information about the available plugins # by running # snapcraft list-plugins plugin: nil
经过我们的重构,我们终于完成了我们的第一个snap应用.目录架构如下:
liuxg@liuxg:~/snappy/desktop/helloworld$ tree -L 3.├── bin│ ├── echo│ ├── env│ ├── evil│ └── sh├── setup│ └── gui│ └── icon.png└── snapcraft.yaml
在这里snapcraft是我们的项目文件,它被用于来打包我们的应用.它的内容如下:
snapcraft.yaml
name: hello-xiaoguoversion: 1.0architectures: [ all ]summary: The 'hello-world' of snapsdescription: | This is a simple snap example that includes a few interesting binaries to demonstrate snaps and their confinement. * hello-world.env - dump the env of commands run inside app sandbox * hello-world.evil - show how snappy sandboxes binaries * hello-world.sh - enter interactive shell that runs in app sandbox * hello-world - simply output textconfinement: strictapps: env: command: bin/env evil: command: bin/evil sh: command: bin/sh hello-world: command: bin/echoparts: hello: plugin: copy files: ./bin: bin
从内容上看,它和我们之前看到的snap几乎是一样的.这里我们使用了copy plugin.如果大家想对snapcraft.yaml中的每一项搞清楚,建议大家阅读文章"Metadata YAML file".在其中,它也描述了哪些项是必须的.
我们可以通过如下的命令来查询目前已经支持的所有的plugins:
liuxg@liuxg:~/snappy/desktop/helloworld$ snapcraft list-pluginsant catkin copy gulp kbuild make nil python2 qmake tar-contentautotools cmake go jdk kernel maven nodejs python3 scons
在我们打包我们的应用之前,我们必须确保在bin目录下的所有文件都是可以执行的:
liuxg@liuxg:~/snappy/desktop/helloworld/bin$ ls -altotal 24drwxrwxr-x 2 liuxg liuxg 4096 7月 13 00:31 .drwxrwxr-x 4 liuxg liuxg 4096 7月 18 10:31 ..-rwxrwxr-x 1 liuxg liuxg 31 7月 12 05:20 echo-rwxrwxr-x 1 liuxg liuxg 27 7月 12 05:20 env-rwxrwxr-x 1 liuxg liuxg 274 7月 12 05:20 evil-rwxrwxr-x 1 liuxg liuxg 209 7月 12 05:20 sh
否则的话,我们需要使用如下的命令来完成:
$ chmod a+x echo
4)编译并执行我们的应用
在我们的项目的根目录下,我们直接打入如下的命令:
$ snapcraft
如果一切顺利的话,我们可以在项目的根目录下看到如下的文件及目录:
liuxg@liuxg:~/snappy/desktop/helloworld$ tree -L 2.├── bin│ ├── echo│ ├── env│ ├── evil│ └── sh├── hello-xiaoguo_1.0_all.snap├── parts│ └── hello├── prime│ ├── bin│ ├── command-env.wrapper│ ├── command-evil.wrapper│ ├── command-hello-world.wrapper│ ├── command-sh.wrapper│ └── meta├── setup│ └── gui├── snapcraft.yaml└── stage └── bin
我们可以看见一个生产的snap文件.一个snap的文件名依赖于如下的规则:
<name>_<version>_<arch>.snap
在我们这个例程中,我们指定architecture为all.
当然,我们也看到了一下其它的文件目录:parts, stage及prime.这些目录是在打包过程中自动生成的.有关更多关于snapcraft的帮助信息,我们可以通过如下的命令来获得:
liuxg@liuxg:~/snappy/desktop/helloworld$ snapcraft --help...The available lifecycle commands are: clean Remove content - cleans downloads, builds or install artifacts. cleanbuild Create a snap using a clean environment managed by lxd. pull Download or retrieve artifacts defined for a part. build Build artifacts defined for a part. Build systems capable of running parallel build jobs will do so unless "--no-parallel-build" is specified. stage Stage the part's built artifacts into the common staging area. prime Final copy and preparation for the snap. snap Create a snap.Parts ecosystem commands update Updates the parts listing from the cloud. define Shows the definition for the cloud part. search Searches the remotes part cache for matching parts.Calling snapcraft without a COMMAND will default to 'snap'...
如果我们想在编译完我们的应用后,不需要留下任何的所安装的包,我们可以使用cleanbuild.它会创建一个lxd容器,在编译完后,后自动销毁:
$ snapcraft cleanbuild
在编译完后,我们可以发现所生产的.snap文件,但是我们可能找不到我们看见的中间文件目录: parts, stage及prime.
如果大家想清除这些在打包过程中的中间文件,我们可以在命令行中打入如下的命令:
$ snapcraft clean
我们可以通过如下的命令来安装我们的应用:
$ sudo snap install hello-xiaoguo_1.0_all.snap --force-dangerous
或如下的方式:
$ sudo snap install hello-xiaoguo_1.0_all.snap --dangerous
在编译一个snap应用时,我们也可以分别对以上的步骤进行操作.在每次操作过后,我们会发现我们的目录结构将会发送改变.
$ snapcraft clean$ snapcraft pull$ snapcraft build$ snapcraft stage$ snapcraft prime$ snapcraft snap prime/
如果我们通过上面的方法进行安装的话,每次安装都会生产一个新的版本,并且占用系统的硬盘资源.我们也可以通过如下的方式来进行安装:
$ sudo snap try prime/
liuxg@liuxg:~/snappy/desktop/helloworld$ snap listName Version Rev Developer Noteshello-world 6.3 27 canonical -hello-xiaoguo 1.0 x2 -ubuntu-core 16.04+20160531.11-56 122 canonical -
如果你已经看到了hello-xiaoguo的应用在上面列表中.那么恭喜你,你已经创建了人生第一个snap.从上面的列表中我们可以看出,它即有一个Version也有一个Rev版本.显然我们的hello-xiaoguo应用已经被成功安装到系统中了.那么我们怎么来运行我们的应用呢?
从我们的snapcraft.yaml文件中,我们可以看出来,我们的包名叫做hello-xiaoguo.在我们的这个包中,我们定义了四个应用:env, evil,sh及hello-world.那么我们运行它们时,我们分别需要使用如下的命令来运行:
$ hello-xiaoguo.env$ hello-xiaoguo.evil$ hello-xiaoguo.sh$ hello-xiaoguo.hello-world
也即,我们使用<<包名>>.<<应用名>>格式来运行我们的应用.比如:
liuxg@liuxg:~/snappy/desktop/helloworld$ hello-xiaoguo.hello-world Hello World!
整个项目的源码在:https://github.com/liu-xiao-guo/helloworld-snap.另外我们特别指出的是,如果你的包的名称和应用名称是一样的,那么你只需要运行包的名称即可.比如你的包的名称是hello,你的应用的名称是hello,那么你直接在命令行中运行hello就可以运行你的应用.
我们可以使用如下的命令来查看我们的snap文件包里的内容:
$ unsquashfs -l hello-xiaoguo_1.0_all.snap
一个snap文件包其实就是一个压缩的squashfs文件.我们也可以通过如下的方式来得到包里所有的内容:
$ unsquashfs hello-xiaoguo_1.0_all.snap $ cd cd squashfs-root # Hack hack hack $ snapcraft snap这里我们就留给开发者们自己做练习.
5)Snap的运行环境
每个应用在被安装到系统的时候,系统将会为这个包里的每个应用生产一个相应的启动脚本.它们可以在如下的路径中找到:
liuxg@liuxg:/snap/bin$ ls -ltotal 52-rwxr-xr-x 1 root root 708 7月 20 15:37 hello-world-rwxr-xr-x 1 root root 783 7月 21 15:13 hello-world-cli-rwxr-xr-x 1 root root 683 7月 20 15:37 hello-world.env-rwxr-xr-x 1 root root 687 7月 20 15:37 hello-world.evil-rwxr-xr-x 1 root root 679 7月 20 15:37 hello-world.sh-rwxr-xr-x 1 root root 743 7月 22 15:30 hello-xiaoguo.createfile-rwxr-xr-x 1 root root 767 7月 22 15:30 hello-xiaoguo.createfiletohome-rwxr-xr-x 1 root root 715 7月 22 15:30 hello-xiaoguo.env-rwxr-xr-x 1 root root 719 7月 22 15:30 hello-xiaoguo.evil-rwxr-xr-x 1 root root 747 7月 22 15:30 hello-xiaoguo.hello-world-rwxr-xr-x 1 root root 711 7月 22 15:30 hello-xiaoguo.sh-rwxr-xr-x 1 root root 726 7月 22 11:32 snappy-debug.security-rwxr-xr-x 1 root root 798 7月 20 10:44 telegram-sergiusens.telegram
我们可以通过cat命令来查看这些脚本的具体的内容.
我们可以执行如下的命令:
$ hello-xiaoguo.env | grep SNAP
通过上面的指令,我们可以得到关于一个snap运行时的所有环境变量:
liuxg@liuxg:~$ hello-xiaoguo.env | grep SNAPSNAP_USER_COMMON=/home/liuxg/snap/hello-xiaoguo/commonSNAP_LIBRARY_PATH=/var/lib/snapd/lib/gl:SNAP_COMMON=/var/snap/hello-xiaoguo/commonSNAP_USER_DATA=/home/liuxg/snap/hello-xiaoguo/x2SNAP_DATA=/var/snap/hello-xiaoguo/x2SNAP_REVISION=x2SNAP_NAME=hello-xiaoguoSNAP_ARCH=amd64SNAP_VERSION=1.0SNAP=/snap/hello-xiaoguo/x2
在我们编程的过程中,我们不必要hard-code我们的变量.比如我们可以在我们的snapcraft中引用$SNAP,它表示我们当前的snap的安装的路径.同时,我们可以看到一个很重要的目录:
SNAP_DATA=/var/snap/hello-xiaoguo/x2
这个目录是我们的snap的私有的目录.我们的snap只能向这个目录或SNAP_USER_DATA进行读写的操作.否则,将会产生安全的错误信息.比如在我们的evil脚本中:
evil
#!/bin/shset -eecho "Hello Evil World!"echo "This example demonstrates the app confinement"echo "You should see a permission denied error next"echo "Haha" > /var/tmp/myevil.txtecho "If you see this line the confinement is not working correctly, please file a bug"
我们通过这个脚本向/var/tmp/中的myevil.txt写入"Haha",它会造成安全的DENIED错误信息:
liuxg@liuxg:~$ hello-xiaoguo.evilHello Evil World!This example demonstrates the app confinementYou should see a permission denied error next/snap/hello-xiaoguo/x2/bin/evil: 9: /snap/hello-xiaoguo/x2/bin/evil: cannot create /var/tmp/myevil.txt: Permission denied
另外一种查找错误的方方法是打开我们的系统的log信息(/var/log/syslog)
8307 comm="fswebcam" requested_mask="r" denied_mask="r" fsuid=0 ouid=0Jul 19 13:27:18 liuxg kernel: [19665.330053] audit: type=1400 audit(1468906038.378:4309): apparmor="DENIED" operation="open" profile="snap.webcam-webui.webcam-webui" name="/etc/fonts/fonts.conf" pid=18307 comm="fswebcam" requested_mask="r" denied_mask="r" fsuid=0 ouid=0Jul 19 13:27:25 liuxg gnome-session[2151]: (nm-applet:2584): nm-applet-WARNING **: ModemManager is not available for modem at /hfp/org/bluez/hci0/dev_F4_B7_E2_CC_F0_56Jul 19 13:27:26 liuxg kernel: [19673.182647] audit: type=1400 audit(1468906046.230:4310): apparmor="DENIED" operation="mknod" profile="snap.hello-xiaoguo.evil" name="/var/tmp/myevil.txt" pid=18314 comm="evil" requested_mask="c" denied_mask="c" fsuid=1000 ouid=1000
或直接使用如下的命令:
liuxg@liuxg:~/snappy/desktop/helloworld$ cat /var/log/syslog | grep DENIED | grep hello-xiaoguoJul 19 13:25:25 liuxg kernel: [19552.926619] audit: type=1400 audit(1468905925.975:4276): apparmor="DENIED" operation="mknod" profile="snap.hello-xiaoguo.evil" name="/var/tmp/myevil.txt" pid=18273 comm="evil" requested_mask="c" denied_mask="c" fsuid=1000 ouid=1000Jul 19 13:27:26 liuxg kernel: [19673.182647] audit: type=1400 audit(1468906046.230:4310): apparmor="DENIED" operation="mknod" profile="snap.hello-xiaoguo.evil" name="/var/tmp/myevil.txt" pid=18314 comm="evil" requested_mask="c" denied_mask="c" fsuid=1000 ouid=1000
这其中最根本的原因是因为我们的snap应用不能访问不属于他自己的目录.这是snap应用最根本的安全机制.我们可以看到上面的operation项.他指出了我们具体的错误操作.
对于snap应用的另外一个安全方面的问题是seccomp violation.对于一个叫做audit的应用来说,我们可以通过如下的方式来得到它的错误信息:
$ sudo grep audit /var/log/syslog
一个seccomp violation的例子可能如下:
audit: type=1326 audit(1430766107.122:16): auid=1000 uid=1000 gid=1000 ses=15 pid=1491 comm="env" exe="/bin/bash" sig=31 arch=40000028 syscall=983045 compat=0 ip=0xb6fb0bd6 code=0x0
$ scmp_sys_resolver 983045set_tls
请注意上面的983045来自于我们的错误信息中的"syscall=983045".这样,我们就可以定位我们的哪些系统调用有问题.
为了说明问题,我们创建一个createfile的脚本:
createfile
#!/bin/shset -eecho "Hello a nice World!"echo "This example demonstrates the app confinement"echo "This app tries to write to its own user directory"echo "Haha" > $HOME/test.txtecho "Succeeded! Please find a file created at $HOME/test.txt"echo "If do not see this, please file a bug"
在我们的snapcraft.yaml中加入:
createfile: command: bin/createfile
重新打包我们的应用:
liuxg@liuxg:~/snappy/desktop/helloworld$ hello-xiaoguo.createfile Hello a nice World!This example demonstrates the app confinementThis app tries to write to its own user directorySucceeded! Please find a file created at /home/liuxg/snap/hello-xiaoguo/x3/test.txtIf do not see this, please file a bug
liuxg@liuxg:~/snappy/desktop/helloworld$ hello-xiaoguo.env | grep homeGPG_AGENT_INFO=/home/liuxg/.gnupg/S.gpg-agent:0:1SNAP_USER_COMMON=/home/liuxg/snap/hello-xiaoguo/commonANDROID_NDK_ROOT=/home/liuxg/android-ndk-r10eSNAP_USER_DATA=/home/liuxg/snap/hello-xiaoguo/x3PWD=/home/liuxg/snappy/desktop/helloworldHOME=/home/liuxg/snap/hello-xiaoguo/x3XAUTHORITY=/home/liuxg/.Xauthority
细心的开发者也许会发现它的定义其实和变量SNAP_USER_DATA是一样的:
liuxg@liuxg:~/snappy/desktop/helloworld$ hello-xiaoguo.env | grep SNAPSNAP_USER_COMMON=/home/liuxg/snap/hello-xiaoguo/commonSNAP_LIBRARY_PATH=/var/lib/snapd/lib/gl:SNAP_COMMON=/var/snap/hello-xiaoguo/commonSNAP_USER_DATA=/home/liuxg/snap/hello-xiaoguo/x3SNAP_DATA=/var/snap/hello-xiaoguo/x3SNAP_REVISION=x3SNAP_NAME=hello-xiaoguoSNAP_ARCH=amd64SNAP_VERSION=1.0SNAP=/snap/hello-xiaoguo/x3
对于一个daemon应用来说,这个$HOME变量的值,是指向$SNAP_DATA而不是$SNAP_USER_DATA.这一点大家要记住.具体的描述可以参阅文章"Snap security policy and sandboxing".
关于security的调试是一件非常麻烦的是.庆幸的是,我们可以利用snappy-debug来帮我们调试.它可以帮我们解析我们到底是哪些地方有错误,并且帮我们解析系统调用的名称等.
$ sudo snap install snappy-debug$ sudo /snap/bin/snappy-debug.security scanlog foo
6)创建一个可以向桌面home写入的app
在上一节的内容中,我们基本上已经看到了snap应用的安全性的一些方面.在我们的snap应用中,假如我们想向我们的桌面电脑中的home里写内容,那应该是怎么办呢?首先,我们创建一个如下的createfiletohome脚本:
createfiletohome:
#!/bin/shset -eecho "Hello a nice World!"echo "This example demonstrates the app confinement"echo "This app tries to write to its own user directory"echo "Haha" > /home/$USER/test.txtecho "Succeeded! Please find a file created at $HOME/test.txt"echo "If do not see this, please file a bug"
在上面我们向我们的用户的home目录写入我们需要的内容.如果我们重新编译并运行我们的应用,我们会发现:
liuxg@liuxg:~/snappy/desktop/helloworld$ hello-xiaoguo.createfiletohome Hello a nice World!This example demonstrates the app confinementThis app tries to write to its own user directory/snap/hello-xiaoguo/x1/bin/createfiletohome: 9: /snap/hello-xiaoguo/x1/bin/createfiletohome: cannot create /home/liuxg/test.txt: Permission denied
显然,它产生了一个错误的信息.我们不可以向我们的用户的home写入任何的内容.那么我们怎么才可以呢?
方法一: 我们使用如下的方法来安装我们的应用:
$ sudo snap install hello-xiaoguo_1.0_all.snap --devmode --force-dangerous
注意上面的--devmode,它表明在开发的过程中,我们的snap应用忽略任何的安全问题,也就是我们的snap将和以前开发的任何应用一样,不接受snap系统所带来的任何的安全的限制.这种方式一般适合在早期开发一个snap应用时使用.等到我们把功能完善后,我们再来完善我们的安全的部分.
针对使用--devmode打包的snap来说(我们也可以在snapcraft.yaml中的confinement设为devmode),我们必须注意的是:
Snaps can be uploaded to the edge and beta channels only
另外特别值得指出的是,如果我们的snapcraft.yaml中的confinement被定义为devmode,那个这个应用将能被"snap find"发现而进行安装.作为开发者本身,你可以通过命令"snap install --devmode"来进行安装测试,普通用户不能使用"snap find/install"来对该应用进行操作.
方法二:我们重新把我们的snapcraft.yaml改写如下:
snapcraft.yaml
name: hello-xiaoguoversion: 1.0architectures: [ all ]summary: The 'hello-world' of snapsdescription: | This is a simple snap example that includes a few interesting binaries to demonstrate snaps and their confinement. * hello-world.env - dump the env of commands run inside app sandbox * hello-world.evil - show how snappy sandboxes binaries * hello-world.sh - enter interactive shell that runs in app sandbox * hello-world - simply output textconfinement: strictapps: env: command: bin/env evil: command: bin/evil sh: command: bin/sh hello-world: command: bin/echo createfile: command: bin/createfile createfiletohome: command: bin/createfiletohome plugs: [home]parts: hello: plugin: copy files: ./bin: bin
在上面,我们在createfiletohome应用下加入了home plug.它表明我们的应用可以访问用户的home目录.在snap系统,如果一个应用想访问另外一个受限的资源或访问一个被其它应用所拥有的资源时,我们可以通过interface来实现.更多的关于snap的interface方面的知识,大家可以参阅Interfaces链接.我们可以通过如下的命令来查看所有的interface:
liuxg@liuxg:~$ snap interfacesSlot Plug:camera -:cups-control -:firewall-control -:gsettings -:home -:locale-control -:log-observe -:modem-manager -:mount-observe -:network -:network-bind -:network-control -:network-manager -:network-observe -:opengl -:optical-drive -:ppp -:pulseaudio -:snapd-control -:system-observe -:timeserver-control -:timezone-control -:unity7 -:x11 -
重新打包我们的应用:
liuxg@liuxg:~/snappy/desktop/helloworld$ hello-xiaoguo.createfiletohome Hello a nice World!This example demonstrates the app confinementThis app tries to write to its own user directorySucceeded! Please find a file created at /home/liuxg/snap/hello-xiaoguo/x1/test.txtIf do not see this, please file a bug
现在,我们再也没有上面显示的那个错误信息了.
所有的源码在:https://github.com/liu-xiao-guo/helloworld-final
7)应用的shell
虽然我们的hello应用非常简单,但是它确实展示了我们很多希望看到的snap应用的一面.在我们的应用中,我们还有一个应用叫做sh.它事件上是一个shell.我们可以通过如下的方式来启动它:
$ hello-xiaoguo.sh
当这个应用被启动后:
liuxg@liuxg:~$ hello-xiaoguo.shLaunching a shell inside the default app confinement. Navigate to yourapp-specific directories with: $ cd $SNAP $ cd $SNAP_DATA $ cd $SNAP_USER_DATAbash-4.3$ env | grep snapSNAP_USER_COMMON=/home/liuxg/snap/hello-xiaoguo/commonSNAP_LIBRARY_PATH=/var/lib/snapd/lib/gl:SNAP_COMMON=/var/snap/hello-xiaoguo/commonSNAP_USER_DATA=/home/liuxg/snap/hello-xiaoguo/x4SNAP_DATA=/var/snap/hello-xiaoguo/x4PATH=/snap/hello-xiaoguo/x4/bin:/snap/hello-xiaoguo/x4/usr/bin:/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/binHOME=/home/liuxg/snap/hello-xiaoguo/x4XDG_DATA_DIRS=/usr/share/ubuntu:/usr/share/gnome:/usr/local/share/:/usr/share/:/var/lib/snapd/desktopSNAP=/snap/hello-xiaoguo/x4bash-4.3$我们可以通过这个shell来完成我们想要的任务.比如:
bash-4.3$ cd /home/liuxgbash-4.3$ pwd/home/liuxgbash-4.3$ touch hello.texttouch: cannot touch 'hello.text': Permission denied
如果大家对snapcraft想了解更多的话,你可以试一下如下的命令:
$ snapcraft tourSnapcraft tour initialized in ./snapcraft-tour/Instructions are in the README, or http://snapcraft.io/create/#tour
我们可以在我们的home里的snapcraft-tour目录中找到我们所需要学习的例程.
0 0
- helloworld Snap例程
- Android HAL:helloworld例程
- OpenCL例程1-HelloWorld
- MOOS例程HelloWorld-详细注释
- EmguCV学习之例程详解(01):HelloWorld
- OpenCV学习之例程详解(01):HelloWorld
- ROS Arduino HelloWorld例程的一些问题
- Symbian入门指南第三章:深入介绍Helloworld例程
- 【Android游戏开发之一】搭建开发环境以HelloWorld例程
- 安装Snap
- 例程
- Android开发之道(1)搭建开发环境以HelloWorld例程
- 零基础学习OpenCL(2)-Qt运行OpenCL的HelloWorld例程
- 迅为Exynos4412开发板例程及注释——QT环境配置与HelloWorld
- helloworld
- HelloWorld
- helloworld
- helloworld
- fatal error C1083: 无法打开包括文件: “jni.h”: No such file or directory
- Python实现windows下模拟按键和鼠标点击的方法
- ros导航资源
- MySQL主键、外键、索引
- 关于maven
- helloworld Snap例程
- iPad Pro 9.7/12.9寸对比测评
- 转常用shell命令
- 发现个不错的OJ题目分类网站
- SSD:Single Shot MultiBox Detector 心得 之神经网路(持续更新中。。。)
- OAuth授权的java实现详解
- Hibernate学习笔记----hibernate的helloworld
- windows下python模拟鼠标点击和键盘输示例
- 【JZOJ4597】现世斩