mirror of
https://github.com/LCTT/TranslateProject.git
synced 2025-02-28 01:01:09 +08:00
Merge remote-tracking branch 'LCTT/master'
This commit is contained in:
commit
f9dfcd4b32
@ -0,0 +1,139 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (warmfrog)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10865-1.html)
|
||||
[#]: subject: (How to use advanced rsync for large Linux backups)
|
||||
[#]: via: (https://opensource.com/article/19/5/advanced-rsync)
|
||||
[#]: author: (Alan Formy-Duval https://opensource.com/users/alanfdoss/users/marcobravo)
|
||||
|
||||
如何使用 rsync 的高级用法进行大型备份
|
||||
=====================================
|
||||
|
||||
> 基础的 `rsync` 命令通常足够来管理你的 Linux 备份,但是额外的选项使大型备份集更快、更强大。
|
||||
|
||||
![Filing papers and documents][1]
|
||||
|
||||
很明显,备份一直是 Linux 世界的热门话题。回到 2017,David Both 为 [Opensource.com][2] 的读者在[使用 rsync 备份 Linux 系统][3]方面提了一些建议,在这年的更早时候,他发起了一项问卷调查询问大家,[在 Linux 中你的 /home 目录的主要备份策略是什么][4],在今年的另一个问卷调查中,Don Watkins 问到,[你使用哪种开源备份解决方案][5]。
|
||||
|
||||
我的回复是 [rsync][6]。我真的非常喜欢 rsync!市场上有大量大而复杂的工具,对于管理磁带机或者存储库设备,这些可能是必要的,但是可能你需要的只是一个简单的开源命令行工具。
|
||||
|
||||
### rsync 基础
|
||||
|
||||
我为一个大概拥有 35,000 开发者并有着几十 TB 文件的全球性机构管理二进制仓库。我经常一次移动或者归档上百 GB 的数据。使用的是 `rsync`。这种经历使我对这个简单的工具充满信心。(所以,是的,我在家使用它来备份我的 Linux 系统)
|
||||
|
||||
基础的 `rsync` 命令很简单。
|
||||
|
||||
|
||||
```
|
||||
rsync -av 源目录 目的地目录
|
||||
```
|
||||
|
||||
实际上,在各种指南中教的 `rsync` 命令在大多数通用情况下都运行的很好。然而,假设我们需要备份大量的数据。例如包含 2,000 个子目录的目录,每个包含 50GB 到 700GB 的数据。在这个目录运行 `rsync` 可能需要大量时间,尤其是当你使用校验选项时(我倾向使用)。
|
||||
|
||||
当我们试图同步大量数据或者通过慢的网络连接时,可能遇到性能问题。让我给你展示一些我使用的方法来确保好的性能和可靠性。
|
||||
|
||||
### rsync 高级用法
|
||||
|
||||
`rsync` 运行时出现的第一行是:“正在发送增量文件列表。” 如果你在网上搜索这一行,你将看到很多类似的问题:为什么它一直运行,或者为什么它似乎挂起了。
|
||||
|
||||
这里是一个基于这个场景的例子。假设我们有一个 `/storage` 的目录,我们想要备份到一个外部 USB 磁盘,我们可以使用下面的命令:
|
||||
|
||||
```
|
||||
rsync -cav /storage /media/WDPassport
|
||||
```
|
||||
|
||||
`-c` 选项告诉 `rsync` 使用文件校验和而不是时间戳来决定改变的文件,这通常消耗的时间更久。为了分解 `/storage` 目录,我通过子目录同步,使用 `find` 命令。这是一个例子:
|
||||
|
||||
|
||||
```
|
||||
find /storage -type d -exec rsync -cav {} /media/WDPassport \;
|
||||
```
|
||||
|
||||
这看起来可以,但是如果 `/storage` 目录有任何文件,它们将被跳过。因此,我们如何同步 `/storage` 目录中的文件呢?同样有一个细微的差别是这些选项将造成 `rsync` 会同步 `.` 目录,该目录是源目录自身;这意味着它会同步子目录两次,这并不是我们想要的。
|
||||
|
||||
长话短说,我的解决方案是一个 “双-递增”脚本。这允许我分解一个目录,例如,当你的家目录有多个大的目录,例如音乐或者家庭照片时,分解 `/home` 目录为单个的用户家目录。
|
||||
|
||||
这是我的脚本的一个例子:
|
||||
|
||||
```
|
||||
HOMES="alan"
|
||||
DRIVE="/media/WDPassport"
|
||||
|
||||
for HOME in $HOMES; do
|
||||
cd /home/$HOME
|
||||
rsync -cdlptgov --delete . /$DRIVE/$HOME
|
||||
find . -maxdepth 1 -type d -not -name "." -exec rsync -crlptgov --delete {} /$DRIVE/$HOME \;
|
||||
done
|
||||
```
|
||||
|
||||
第一个 `rsync` 命令拷贝它在源目录中发现的文件和目录。然而,它将目录留着不处理,因此我们能够通过 `find` 命令迭代它们。这通过传递 `-d` 参数来完成,它告诉 `rsync` 不要递归目录。
|
||||
|
||||
|
||||
```
|
||||
-d, --dirs 传输目录而不递归
|
||||
```
|
||||
|
||||
然后 `find` 命令传递每个目录来单独运行 `rsync`。之后 `rsync` 拷贝目录的内容。这通过传递 `-r` 参数来完成,它告诉 `rsync` 要递归目录。
|
||||
|
||||
|
||||
```
|
||||
-r, --recursive 递归进入目录
|
||||
```
|
||||
|
||||
这使得 `rsync` 使用的增量文件保持在一个合理的大小。
|
||||
|
||||
大多数 `rsync` 指南为了简便使用 `-a` (或者 `archive`) 参数。这实际是一个复合参数。
|
||||
|
||||
```
|
||||
-a, --archive 归档模式;等价于 -rlptgoD(没有 -H,-A,-X)
|
||||
```
|
||||
|
||||
我传递的其他参数包含在 `a` 中;这些是 `-l`、`-p`、`-t`、`-g`和 `-o`。
|
||||
|
||||
|
||||
```
|
||||
-l, --links 复制符号链接作为符号链接
|
||||
-p, --perms 保留权限
|
||||
-t, --times 保留修改时间
|
||||
-g, --group 保留组
|
||||
-o, --owner 保留拥有者(只适用于超级管理员)
|
||||
```
|
||||
|
||||
`--delete` 选项告诉 `rsync` 删除目的地目录中所有在源目录不存在的任意文件。这种方式,运行的结果仅仅是复制。你同样可以排除 `.Trash` 目录或者 MacOS 创建的 `.DS_Store` 文件。
|
||||
|
||||
|
||||
```
|
||||
-not -name ".Trash*" -not -name ".DS_Store"
|
||||
```
|
||||
|
||||
### 注意
|
||||
|
||||
最后一条建议: `rsync` 可以是破坏性的命令。幸运的是,它的睿智的创造者提供了 “空运行” 的能力。如果我们加入 `n` 选项,rsync 会显示预期的输出但不写任何数据。
|
||||
|
||||
|
||||
```
|
||||
`rsync -cdlptgovn --delete . /$DRIVE/$HOME`
|
||||
```
|
||||
|
||||
这个脚本适用于非常大的存储规模和高延迟或者慢链接的情况。一如既往,我确信仍有提升的空间。如果你有任何建议,请在下方评论中分享。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/5/advanced-rsync
|
||||
|
||||
作者:[Alan Formy-Duval][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[warmfrog](https://github.com/warmfrog)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/alanfdoss/users/marcobravo
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/documents_papers_file_storage_work.png?itok=YlXpAqAJ (Filing papers and documents)
|
||||
[2]: http://Opensource.com
|
||||
[3]: https://linux.cn/article-8237-1.html
|
||||
[4]: https://opensource.com/poll/19/4/backup-strategy-home-directory-linux
|
||||
[5]: https://opensource.com/article/19/2/linux-backup-solutions
|
||||
[6]: https://en.wikipedia.org/wiki/Rsync
|
@ -1,353 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (cycoe)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Using Pygame to move your game character around)
|
||||
[#]: via: (https://opensource.com/article/17/12/game-python-moving-player)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
Using Pygame to move your game character around
|
||||
======
|
||||
In the fourth part of this series, learn how to code the controls needed to move a game character.
|
||||

|
||||
|
||||
In the first article in this series, I explained how to use Python to create a simple, [text-based dice game][1]. In the second part, we began building a game from scratch, starting with [creating the game's environment][2]. And, in the third installment, we [created a player sprite][3] and made it spawn in your (rather empty) game world. As you've probably noticed, a game isn't much fun if you can't move your character around. In this article, we'll use Pygame to add keyboard controls so you can direct your character's movement.
|
||||
|
||||
There are functions in Pygame to add other kinds of controls, but since you certainly have a keyboard if you're typing out Python code, that's what we'll use. Once you understand keyboard controls, you can explore other options on your own.
|
||||
|
||||
You created a key to quit your game in the second article in this series, and the principle is the same for movement. However, getting your character to move is a little more complex.
|
||||
|
||||
Let's start with the easy part: setting up the controller keys.
|
||||
|
||||
### Setting up keys for controlling your player sprite
|
||||
|
||||
Open your Python game script in IDLE, Ninja-IDE, or a text editor.
|
||||
|
||||
Since the game must constantly "listen" for keyboard events, you'll be writing code that needs to run continuously. Can you figure out where to put code that needs to run constantly for the duration of the game?
|
||||
|
||||
If you answered "in the main loop," you're correct! Remember that unless code is in a loop, it will run (at most) only once—and it may not run at all if it's hidden away in a class or function that never gets used.
|
||||
|
||||
To make Python monitor for incoming key presses, add this code to the main loop. There's no code to make anything happen yet, so use `print` statements to signal success. This is a common debugging technique.
|
||||
|
||||
```
|
||||
while main == True:
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
pygame.quit(); sys.exit()
|
||||
main = False
|
||||
|
||||
if event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_LEFT or event.key == ord('a'):
|
||||
print('left')
|
||||
if event.key == pygame.K_RIGHT or event.key == ord('d'):
|
||||
print('right')
|
||||
if event.key == pygame.K_UP or event.key == ord('w'):
|
||||
print('jump')
|
||||
|
||||
if event.type == pygame.KEYUP:
|
||||
if event.key == pygame.K_LEFT or event.key == ord('a'):
|
||||
print('left stop')
|
||||
if event.key == pygame.K_RIGHT or event.key == ord('d'):
|
||||
print('right stop')
|
||||
if event.key == ord('q'):
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
main = False
|
||||
```
|
||||
|
||||
Some people prefer to control player characters with the keyboard characters W, A, S, and D, and others prefer to use arrow keys. Be sure to include both options.
|
||||
|
||||
**Note: **It's vital that you consider all of your users when programming. If you write code that works only for you, it's very likely that you'll be the only one who uses your application. More importantly, if you seek out a job writing code for money, you are expected to write code that works for everyone. Giving your users choices, such as the option to use either arrow keys or WASD, is a sign of a good programmer.
|
||||
|
||||
Launch your game using Python, and watch the console window for output as you press the right, left, and up arrows, or the A, D, and W keys.
|
||||
|
||||
```
|
||||
$ python ./your-name_game.py
|
||||
left
|
||||
left stop
|
||||
right
|
||||
right stop
|
||||
jump
|
||||
```
|
||||
|
||||
This confirms that Pygame detects key presses correctly. Now it's time to do the hard work of making the sprite move.
|
||||
|
||||
### Coding the player movement function
|
||||
|
||||
To make your sprite move, you must create a property for your sprite that represents movement. When your sprite is not moving, this variable is set to `0`.
|
||||
|
||||
If you are animating your sprite, or should you decide to animate it in the future, you also must track frames to enable the walk cycle to stay on track.
|
||||
|
||||
Create the variables in the Player class. The first two lines are for context (you already have them in your code, if you've been following along), so add only the last three:
|
||||
|
||||
```
|
||||
def __init__(self):
|
||||
pygame.sprite.Sprite.__init__(self)
|
||||
self.movex = 0 # move along X
|
||||
self.movey = 0 # move along Y
|
||||
self.frame = 0 # count frames
|
||||
```
|
||||
|
||||
With those variables set, it's time to code the sprite's movement.
|
||||
|
||||
The player sprite doesn't need to respond to control all the time; sometimes it will not be moving. The code that controls the sprite, therefore, is only one small part of all the things the player sprite will do. When you want to make an object in Python do something independent of the rest of its code, you place your new code in a function. Python functions start with the keyword `def`, which stands for define.
|
||||
|
||||
Make a function in your Player class to add some number of pixels to your sprite's position on screen. Don't worry about how many pixels you add yet; that will be decided in later code.
|
||||
|
||||
```
|
||||
def control(self,x,y):
|
||||
'''
|
||||
control player movement
|
||||
'''
|
||||
self.movex += x
|
||||
self.movey += y
|
||||
```
|
||||
|
||||
To move a sprite in Pygame, you have to tell Python to redraw the sprite in its new location—and where that new location is.
|
||||
|
||||
Since the Player sprite isn't always moving, the updates need to be only one function within the Player class. Add this function after the `control` function you created earlier.
|
||||
|
||||
To make it appear that the sprite is walking (or flying, or whatever it is your sprite is supposed to do), you need to change its position on screen when the appropriate key is pressed. To get it to move across the screen, you redefine its position, designated by the `self.rect.x` and `self.rect.y` properties, to its current position plus whatever amount of `movex` or `movey` is applied. (The number of pixels the move requires is set later.)
|
||||
|
||||
```
|
||||
def update(self):
|
||||
'''
|
||||
Update sprite position
|
||||
'''
|
||||
self.rect.x = self.rect.x + self.movex
|
||||
```
|
||||
|
||||
Do the same thing for the Y position:
|
||||
|
||||
```
|
||||
self.rect.y = self.rect.y + self.movey
|
||||
```
|
||||
|
||||
For animation, advance the animation frames whenever your sprite is moving, and use the corresponding animation frame as the player image:
|
||||
|
||||
```
|
||||
# moving left
|
||||
if self.movex < 0:
|
||||
self.frame += 1
|
||||
if self.frame > 3*ani:
|
||||
self.frame = 0
|
||||
self.image = self.images[self.frame//ani]
|
||||
|
||||
# moving right
|
||||
if self.movex > 0:
|
||||
self.frame += 1
|
||||
if self.frame > 3*ani:
|
||||
self.frame = 0
|
||||
self.image = self.images[(self.frame//ani)+4]
|
||||
```
|
||||
|
||||
Tell the code how many pixels to add to your sprite's position by setting a variable, then use that variable when triggering the functions of your Player sprite.
|
||||
|
||||
First, create the variable in your setup section. In this code, the first two lines are for context, so just add the third line to your script:
|
||||
|
||||
```
|
||||
player_list = pygame.sprite.Group()
|
||||
player_list.add(player)
|
||||
steps = 10 # how many pixels to move
|
||||
```
|
||||
|
||||
Now that you have the appropriate function and variable, use your key presses to trigger the function and send the variable to your sprite.
|
||||
|
||||
Do this by replacing the `print` statements in your main loop with the Player sprite's name (player), the function (.control), and how many steps along the X axis and Y axis you want the player sprite to move with each loop.
|
||||
|
||||
```
|
||||
if event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_LEFT or event.key == ord('a'):
|
||||
player.control(-steps,0)
|
||||
if event.key == pygame.K_RIGHT or event.key == ord('d'):
|
||||
player.control(steps,0)
|
||||
if event.key == pygame.K_UP or event.key == ord('w'):
|
||||
print('jump')
|
||||
|
||||
if event.type == pygame.KEYUP:
|
||||
if event.key == pygame.K_LEFT or event.key == ord('a'):
|
||||
player.control(steps,0)
|
||||
if event.key == pygame.K_RIGHT or event.key == ord('d'):
|
||||
player.control(-steps,0)
|
||||
if event.key == ord('q'):
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
main = False
|
||||
```
|
||||
|
||||
Remember, `steps` is a variable representing how many pixels your sprite moves when a key is pressed. If you add 10 pixels to the location of your player sprite when you press D or the right arrow, then when you stop pressing that key you must subtract 10 (`-steps`) to return your sprite's momentum back to 0.
|
||||
|
||||
Try your game now. Warning: it won't do what you expect.
|
||||
|
||||
Why doesn't your sprite move yet? Because the main loop doesn't call the `update` function.
|
||||
|
||||
Add code to your main loop to tell Python to update the position of your player sprite. Add the line with the comment:
|
||||
|
||||
```
|
||||
player.update() # update player position
|
||||
player_list.draw(world)
|
||||
pygame.display.flip()
|
||||
clock.tick(fps)
|
||||
```
|
||||
|
||||
Launch your game again to witness your player sprite move across the screen at your bidding. There's no vertical movement yet because those functions will be controlled by gravity, but that's another lesson for another article.
|
||||
|
||||
In the meantime, if you have access to a joystick, try reading Pygame's documentation for its [joystick][4] module and see if you can make your sprite move that way. Alternately, see if you can get the [mouse][5] to interact with your sprite.
|
||||
|
||||
Most importantly, have fun!
|
||||
|
||||
### All the code used in this tutorial
|
||||
|
||||
For your reference, here is all the code used in this series of articles so far.
|
||||
|
||||
```
|
||||
#!/usr/bin/env python3
|
||||
# draw a world
|
||||
# add a player and player control
|
||||
# add player movement
|
||||
|
||||
# GNU All-Permissive License
|
||||
# Copying and distribution of this file, with or without modification,
|
||||
# are permitted in any medium without royalty provided the copyright
|
||||
# notice and this notice are preserved. This file is offered as-is,
|
||||
# without any warranty.
|
||||
|
||||
import pygame
|
||||
import sys
|
||||
import os
|
||||
|
||||
'''
|
||||
Objects
|
||||
'''
|
||||
|
||||
class Player(pygame.sprite.Sprite):
|
||||
'''
|
||||
Spawn a player
|
||||
'''
|
||||
def __init__(self):
|
||||
pygame.sprite.Sprite.__init__(self)
|
||||
self.movex = 0
|
||||
self.movey = 0
|
||||
self.frame = 0
|
||||
self.images = []
|
||||
for i in range(1,5):
|
||||
img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
|
||||
img.convert_alpha()
|
||||
img.set_colorkey(ALPHA)
|
||||
self.images.append(img)
|
||||
self.image = self.images[0]
|
||||
self.rect = self.image.get_rect()
|
||||
|
||||
def control(self,x,y):
|
||||
'''
|
||||
control player movement
|
||||
'''
|
||||
self.movex += x
|
||||
self.movey += y
|
||||
|
||||
def update(self):
|
||||
'''
|
||||
Update sprite position
|
||||
'''
|
||||
|
||||
self.rect.x = self.rect.x + self.movex
|
||||
self.rect.y = self.rect.y + self.movey
|
||||
|
||||
# moving left
|
||||
if self.movex < 0:
|
||||
self.frame += 1
|
||||
if self.frame > 3*ani:
|
||||
self.frame = 0
|
||||
self.image = self.images[self.frame//ani]
|
||||
|
||||
# moving right
|
||||
if self.movex > 0:
|
||||
self.frame += 1
|
||||
if self.frame > 3*ani:
|
||||
self.frame = 0
|
||||
self.image = self.images[(self.frame//ani)+4]
|
||||
|
||||
|
||||
'''
|
||||
Setup
|
||||
'''
|
||||
worldx = 960
|
||||
worldy = 720
|
||||
|
||||
fps = 40 # frame rate
|
||||
ani = 4 # animation cycles
|
||||
clock = pygame.time.Clock()
|
||||
pygame.init()
|
||||
main = True
|
||||
|
||||
BLUE = (25,25,200)
|
||||
BLACK = (23,23,23 )
|
||||
WHITE = (254,254,254)
|
||||
ALPHA = (0,255,0)
|
||||
|
||||
world = pygame.display.set_mode([worldx,worldy])
|
||||
backdrop = pygame.image.load(os.path.join('images','stage.png')).convert()
|
||||
backdropbox = world.get_rect()
|
||||
player = Player() # spawn player
|
||||
player.rect.x = 0
|
||||
player.rect.y = 0
|
||||
player_list = pygame.sprite.Group()
|
||||
player_list.add(player)
|
||||
steps = 10 # how fast to move
|
||||
|
||||
'''
|
||||
Main loop
|
||||
'''
|
||||
while main == True:
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
pygame.quit(); sys.exit()
|
||||
main = False
|
||||
|
||||
if event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_LEFT or event.key == ord('a'):
|
||||
player.control(-steps,0)
|
||||
if event.key == pygame.K_RIGHT or event.key == ord('d'):
|
||||
player.control(steps,0)
|
||||
if event.key == pygame.K_UP or event.key == ord('w'):
|
||||
print('jump')
|
||||
|
||||
if event.type == pygame.KEYUP:
|
||||
if event.key == pygame.K_LEFT or event.key == ord('a'):
|
||||
player.control(steps,0)
|
||||
if event.key == pygame.K_RIGHT or event.key == ord('d'):
|
||||
player.control(-steps,0)
|
||||
if event.key == ord('q'):
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
main = False
|
||||
|
||||
# world.fill(BLACK)
|
||||
world.blit(backdrop, backdropbox)
|
||||
player.update()
|
||||
player_list.draw(world) #refresh player position
|
||||
pygame.display.flip()
|
||||
clock.tick(fps)
|
||||
```
|
||||
|
||||
You've come far and learned much, but there's a lot more to do. In the next few articles, you'll add enemy sprites, emulated gravity, and lots more. In the mean time, practice with Python!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/17/12/game-python-moving-player
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/article/17/10/python-101
|
||||
[2]: https://opensource.com/article/17/12/program-game-python-part-2-creating-game-world
|
||||
[3]: https://opensource.com/article/17/12/program-game-python-part-3-spawning-player
|
||||
[4]: http://pygame.org/docs/ref/joystick.html
|
||||
[5]: http://pygame.org/docs/ref/mouse.html#module-pygame.mouse
|
@ -1,61 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Get started with Libki to manage public user computer access)
|
||||
[#]: via: (https://opensource.com/article/19/5/libki-computer-access)
|
||||
[#]: author: (Don Watkins https://opensource.com/users/don-watkins/users/tony-thomas)
|
||||
|
||||
Get started with Libki to manage public user computer access
|
||||
======
|
||||
Libki is a cross-platform, computer reservation and time management
|
||||
system.
|
||||
![][1]
|
||||
|
||||
Libraries, schools, colleges, and other organizations that provide public computers need a good way to manage users' access—otherwise, there's no way to prevent some people from monopolizing the machines and ensure everyone has a fair amount of time. This is the problem that [Libki][2] was designed to solve.
|
||||
|
||||
Libki is an open source, cross-platform, computer reservation and time management system for Windows and Linux PCs. It provides a web-based server and a web-based administration system that staff can use to manage computer access, including creating and deleting users, setting time limits on accounts, logging out and banning users, and setting access restrictions.
|
||||
|
||||
According to lead developer [Kyle Hall][3], Libki is mainly used for PC time control as an open source alternative to Envisionware's proprietary computer access control software. When users log into a Libki-managed computer, they get a block of time to use the computer; once that time is up, they are logged off. The default setting is 45 minutes, but that can easily be adjusted using the web-based administration system. Some organizations offer 24 hours of access before logging users off, and others use it to track usage without setting time limits.
|
||||
|
||||
Kyle is currently lead developer at [ByWater Solutions][4], which provides open source software solutions (including Libki) to libraries. He developed Libki early in his career when he was the IT tech at the [Meadville Public Library][5] in Pennsylvania. He was occasionally asked to cover the children's room during lunch breaks for other employees. The library used a paper sign-up sheet to manage access to the computers in the children's room, which meant constant supervision and checking to ensure equitable access for the people who came there.
|
||||
|
||||
Kyle said, "I found this system to be cumbersome and awkward, and I wanted to find a solution. That solution needed to be both FOSS and cross-platform. In the end, no existing software package suited our particular needs, and that is why I developed Libki."
|
||||
|
||||
Or, as Libki's website proclaims, "Libki was born of the need to avoid interacting with teenagers and now allows librarians to avoid interacting with teenagers around the world!"
|
||||
|
||||
### Easy to set up and use
|
||||
|
||||
I recently decided to try Libki in our local public library, where I frequently volunteer. I followed the [documentation][6] for the automatic installation, using Ubuntu 18.04 Server, and very quickly had it up and running.
|
||||
|
||||
I am planning to support Libki in our local library, but I wondered about libraries that don't have someone with IT experience or the ability to build and deploy a server. Kyle says, "ByWater Solutions can cloud-host a Libki server, which makes maintenance and management much simpler for everyone."
|
||||
|
||||
Kyle says ByWater is not planning to bundle Libki with its most popular offering, open source integrated library system (ILS) Koha, or any of the other [projects][7] it supports. "Libki and Koha are different [types of] software serving different needs, but they definitely work well together in a library setting. In fact, it was quite early on that I developed Libki's SIP2 integration so it could support single sign-on using Koha," he says.
|
||||
|
||||
### How you can contribute
|
||||
|
||||
Libki client is licensed under the GPLv3 and Libki server is licensed under the AGPLv3. Kyle says he would love Libki to have a more active and robust community, and the project is always looking for new people to join its [contributors][8]. If you would like to participate, visit [Libki's Community page][9] and join the mailing list.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/5/libki-computer-access
|
||||
|
||||
作者:[Don Watkins ][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/don-watkins/users/tony-thomas
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/desk_clock_job_work.jpg?itok=Nj4fuhl6
|
||||
[2]: https://libki.org/
|
||||
[3]: https://www.linkedin.com/in/kylemhallinfo/
|
||||
[4]: https://opensource.com/article/19/4/software-libraries
|
||||
[5]: https://meadvillelibrary.org/
|
||||
[6]: https://manual.libki.org/master/libki-manual.html#_automatic_installation
|
||||
[7]: https://bywatersolutions.com/projects
|
||||
[8]: https://github.com/Libki/libki-server/graphs/contributors
|
||||
[9]: https://libki.org/community/
|
@ -1,5 +1,5 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
170
sources/tech/20190510 PHP in 2019.md
Normal file
170
sources/tech/20190510 PHP in 2019.md
Normal file
@ -0,0 +1,170 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (PHP in 2019)
|
||||
[#]: via: (https://stitcher.io/blog/php-in-2019)
|
||||
[#]: author: (Brent https://stitcher.io/blog/php-in-2019)
|
||||
|
||||
PHP in 2019
|
||||
======
|
||||
|
||||
|
||||
Do you remember the popular "[PHP: a fractal of bad design][3]" blog post? The first time I read it, I was working in a crappy place with lots of legacy PHP projects. This article got me wondering whether I should just quit and go do something entirely different than programming.
|
||||
|
||||
Luckily for me I was able to switch jobs shortly thereafter and, more importantly, PHP managed to evolve quite a bit since the 5.* days. Today I'm addressing the people who are either not programming in PHP anymore, or are stuck in legacy projects.
|
||||
|
||||
Spoiler: some things still suck today, just like almost every programming language has its quirks. Many core functions still have their inconsistent method signatures, there are still confusing configuration settings, there are still many developers out there writing crappy code — because they have to, or because they don't know better.
|
||||
|
||||
Today I want to look at the bright side: let's focus on the things that have changed and ways to write clean and maintainable PHP code. I want to ask you to set aside any prejudice for just a few minutes.
|
||||
|
||||
Afterwards you're free to think exactly the same about PHP as you did before. Though chances are you will be surprised by some of the improvements made to PHP in the last few years.
|
||||
|
||||
### TL;DR
|
||||
|
||||
* PHP is actively developed with a new release each year
|
||||
* Performance since the PHP 5 era has doubled, if not tripled
|
||||
* There's a extremely active eco system of frameworks, packages and platforms
|
||||
* PHP has had lots of new features added to it over the past few years, and the language keeps evolving
|
||||
* Tooling like static analysers has matured over the past years, and only keeps growing
|
||||
|
||||
|
||||
|
||||
Update: people asked me to show some actual code. I'm happy to say that's possible! Here's the [source code][4] of one of my hobby projects, written in PHP and Laravel; and [here][5] is a list of a few hundred OSS packages we maintain at our office. Both are good examples of what modern PHP projects look like.
|
||||
|
||||
Let's start.
|
||||
|
||||
### History summarized
|
||||
|
||||
For good measure, let's quickly review PHP's release cycle today. We're at PHP 7.3 now, with 7.4 expected at the end of 2019. PHP 8.0 will be the next version after 7.4.
|
||||
|
||||
Ever since the late 5.* era, the core team tries to keep a yearly release cycle, and have succeeded in doing so for the past four years.
|
||||
|
||||
In general, every new release is actively supported for two years, and gets one more year of "security fixes only". The goal is to motivate PHP developers to stay up-to-date as much as possible: small upgrades every year are way more easy than making the jump between 5.4 to 7.0, for example.
|
||||
|
||||
An active overview of PHP's timeline can be found [here][6].
|
||||
|
||||
Lastly, PHP 5.6 was the latest 5.* release, with 7.0 being the next one. If you want to know what happened to PHP 6, you can listen to the [PHP Roundtable podcast][7].
|
||||
|
||||
With that out of the way, let's debunk some common misconceptions about modern PHP.
|
||||
|
||||
### PHP's performance
|
||||
Back in the 5.* days, PHP's performance was… average at best. With 7.0 though, big pieces of PHP's core were rewritten from the ground up, resulting in two or three times performance increases.
|
||||
|
||||
Words don't suffice though. Let's look at benchmarks. Luckily other people have spent lots of time in benchmarking PHP performance. I find that [Kinsta][8] has a good updated list.
|
||||
|
||||
Ever since the 7.0 upgrade, performance only increased. So much that PHP web applications have comparable — in some cases better — performance than web frameworks in other languages. Take a look at this [extensive benchmark suite][9].
|
||||
|
||||
Sure PHP frameworks won't outperform C and Rust, but they do quite a lot better than Rails or Django, and are comparable to ExpressJS.
|
||||
|
||||
### Frameworks and ecosystem
|
||||
|
||||
Speaking of frameworks: PHP isn't just WordPress anymore. Let me tell you something as a professional PHP developer: WordPress isn't in any way representative of the contemporary ecosystem.
|
||||
|
||||
In general there are two major web application frameworks, and a few smaller ones: [Symfony][10] and [Laravel][11]. Sure there's also Zend, Yii, Cake, Code Igniter etc. — but if you want to know what modern PHP development looks like, you're good with one of these two.
|
||||
|
||||
Both frameworks have a large ecosystem of packages and products. Ranging from admin panels and CRMs to standalone packages, CI to profilers, numerous services like web sockets servers, queuing managers, payment integrations; honestly there's too much to list.
|
||||
|
||||
These frameworks are meant for actual development though. If you're in need of pure content management, platforms like WordPress and CraftCMS are only improving more and more.
|
||||
|
||||
One way to measure the current state of PHP's ecosystem is to look at Packagist, the main package repository for PHP. It has seen exponential growth. With ±25 million downloads a day, it's fair to say that the PHP ecosystem isn't the small underdog it used to be.
|
||||
|
||||
Take a look at this graph, listing the amount of packages and versions over time. It can also be found on [the Packagist website][12].
|
||||
|
||||
![][13]
|
||||
|
||||
Besides application frameworks and CMSs, we've also seen the rise of asynchronous frameworks the past years.
|
||||
|
||||
These are frameworks and servers, written in PHP or other languages, that allow users to run truly asynchronous PHP. A few examples include [Swoole][14], [Amp][15] and [ReactPHP][16].
|
||||
|
||||
Since we've ventured into the async world, stuff like web sockets and applications with lots of IO have become actually relevant in the PHP world.
|
||||
|
||||
There has also been talk on the internals mailing list — the place where core developers discuss the development of the language — to [add libuv to the core][17]. For those unaware of libuv: it's the same library Node.js uses to allow all its asynchronicity.
|
||||
|
||||
### The language itself
|
||||
|
||||
While `async` and `await` are not available yet, lots of improvements to the language itself have been made over the past years. Here's a non-exhaustive list of new features in PHP:
|
||||
|
||||
+ Short closures
|
||||
+ Null coalescing operator
|
||||
+ Traits
|
||||
+ Typed properties
|
||||
+ Spread operator
|
||||
+ JIT compiler
|
||||
+ FFI
|
||||
+ Anonymous classes
|
||||
+ Return type declarations
|
||||
+ Contemporary cryptography
|
||||
+ Generators
|
||||
+ Lots more
|
||||
|
||||
While we're on the topic of language features, let's also talk about the process of how the language is developed today. There's an active core team of volunteers who move the language forward, though the community is allowed to propose RFCs.
|
||||
|
||||
Next, these RFCs are discussed on the "internals" mailing list, which can also be [read online][18]. Before a new language feature is added, there must be a vote. Only RFC with at least a 2/3 majority are allowed in the core.
|
||||
|
||||
There are probably around 100 people allowed to vote, though you're not required to vote on each RFC. Members of the core team are of course allowed to vote, they have to maintain the code base. Besides them, there's a group of people who have been individually picked from the PHP community. These people include maintainers of the PHP docs, contributors to the PHP project as a whole, and prominent developers in the PHP community.
|
||||
|
||||
While most of core development is done on a voluntary basis, one of the core PHP developers, Nikita Popov, has recently been [employed by JetBrains][19] to work on the language full time. Another example is the Linux foundation who recently decided to [invest into Zend framework][20]. Employments and acquisitions like these ensure stability for the future development of PHP.
|
||||
|
||||
### Tooling
|
||||
|
||||
Besides the core itself, we've seen an increase in tools around it the past few years. What comes to mind are static analysers like [Psalm][21], created by Vimeo; [Phan][22] and [PHPStan][23].
|
||||
|
||||
These tools will statically analyse your PHP code and report any type errors, possible bugs etc. In some way, the functionality they provide can be compared to TypeScript, though for now the language isn't transpiled, so no custom syntax is allowed.
|
||||
|
||||
Even though that means we need to rely on docblocks, Rasmus Lerdorf, the original creator of PHP, did mention the idea of [adding a static analysis engine][24] to the core. While there would be lots of potential, it is a huge undertaking.
|
||||
|
||||
Speaking of transpiling, and inspired by the JavaScript community; there have been efforts to extend PHPs syntax in user land. A project called [Pre][25] does exactly that: allow new PHP syntax which is transpiled to normal PHP code.
|
||||
|
||||
While the idea has proven itself in the JavaScript world, it could only work in PHP if proper IDE- and static analysis support was provided. It's a very interesting idea, but has to grow before being able to call it "mainstream".
|
||||
|
||||
### In closing
|
||||
|
||||
All that being said, feel free to still think of PHP as a crappy language. While the language definitely has its drawbacks and 20 years of legacy to carry with it; I can say in confidence that I enjoy working with it.
|
||||
|
||||
In my experience, I'm able to create reliable, maintainable and quality software. The clients I work for are happy with the end result, as am I.
|
||||
|
||||
While it's still possible to do lots of messed up things with PHP, I'd say it's a great choice for web development if used wise and correct.
|
||||
|
||||
Don't you agree? Let me know why! You can reach me via [Twitter][2] or [e-mail][26].
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://stitcher.io/blog/php-in-2019
|
||||
|
||||
作者:[Brent][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://stitcher.io/blog/php-in-2019
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://stitcher.io/
|
||||
[2]: https://twitter.com/brendt_gd
|
||||
[3]: https://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/
|
||||
[4]: https://github.com/brendt/aggregate.stitcher.io
|
||||
[5]: https://spatie.be/open-source/packages
|
||||
[6]: https://www.php.net/supported-versions.php
|
||||
[7]: https://www.phproundtable.com/episode/what-happened-to-php-6
|
||||
[8]: https://kinsta.com/blog/php-benchmarks/
|
||||
[9]: https://github.com/the-benchmarker/web-frameworks
|
||||
[10]: https://symfony.com/
|
||||
[11]: https://laravel.com/
|
||||
[12]: https://packagist.org/statistics
|
||||
[13]: https://stitcher.io/resources/img/blog/php-in-2019/packagist.png
|
||||
[14]: https://www.swoole.co.uk/
|
||||
[15]: https://amphp.org/
|
||||
[16]: https://reactphp.org/
|
||||
[17]: https://externals.io/message/102415#102415
|
||||
[18]: https://externals.io/
|
||||
[19]: https://blog.jetbrains.com/phpstorm/2019/01/nikita-popov-joins-phpstorm-team/
|
||||
[20]: https://getlaminas.org/
|
||||
[21]: https://github.com/vimeo/psalm
|
||||
[22]: https://github.com/phan/phan
|
||||
[23]: https://github.com/phpstan/phpstan
|
||||
[24]: https://externals.io/message/101477#101592
|
||||
[25]: https://preprocess.io/
|
||||
[26]: mailto:brendt@stitcher.io
|
@ -0,0 +1,164 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Querying 10 years of GitHub data with GHTorrent and Libraries.io)
|
||||
[#]: via: (https://opensource.com/article/19/5/chaossearch-github-ghtorrent)
|
||||
[#]: author: (Pete Cheslock https://opensource.com/users/petecheslock/users/ghaff/users/payalsingh/users/davidmstokes)
|
||||
|
||||
Querying 10 years of GitHub data with GHTorrent and Libraries.io
|
||||
======
|
||||
There is a way to explore GitHub data without any local infrastructure
|
||||
using open source datasets.
|
||||
![magnifying glass on computer screen][1]
|
||||
|
||||
I’m always on the lookout for new datasets that we can use to show off the power of my team's work. [**CHAOS** SEARCH][2] turns your [Amazon S3][3] object storage data into a fully searchable [Elasticsearch][4]-like cluster. With the Elasticsearch API or tools like [Kibana][5], you can then query whatever data you find.
|
||||
|
||||
I was excited when I found the [GHTorrent][6] project to explore. GHTorrent aims to build an offline version of all data available through the GitHub APIs. If datasets are your thing, this is a project worth checking out or even consider [donating one of your GitHub API keys][7].
|
||||
|
||||
### Accessing GHTorrent data
|
||||
|
||||
There are many ways to gain access to and use [GHTorrent’s data][8], which is available in [NDJSON][9]** **format. This project does a great job making the data available in multiple forms, including[CSV][10] for restoring into a [MySQL][11] database, [MongoDB][12] dumps of all objects, and Google Big Query** **(free) for exporting data directly into Google’s object storage. There is one caveat: this dataset has a nearly complete dataset from 2008 to 2017 but is not as complete from 2017 to today. That will impact our ability to query with certainty, but it is still an exciting amount of information.
|
||||
|
||||
I chose Google Big Query to avoid running any database myself, so I was quickly able to download a full corpus of data including users and projects. **CHAOS** SEARCH can natively analyze the NDJSON format, so after uploading the data to Amazon S3 I was able to index it in just a few minutes. The **CHAOS** SEARCH platform doesn’t require users to set up index schemas or define mappings for their data, so it discovered all of the fields—strings, integers, etc.—itself.
|
||||
|
||||
With my data fully indexed and ready for search and aggregation, I wanted to dive in and see what insights we can learn, like which software languages are the most popular for GitHub projects.
|
||||
|
||||
(A note on formatting: this is a valid JSON query that we won't format correctly here to avoid scroll fatigue. To properly format it, you can copy it locally and send to a command-line utility like [jq][13].)
|
||||
|
||||
|
||||
```
|
||||
`{"aggs":{"2":{"date_histogram":{"field":"root.created_at","interval":"1M","time_zone":"America/New_York","min_doc_count":1}}},"size":0,"_source":{"excludes":[]},"stored_fields":["*"],"script_fields":{},"docvalue_fields":["root.created_at","root.updated_at"],"query":{"bool":{"must":[],"filter":[{"match_all":{}}],"should":[],"must_not":[{"match_phrase":{"root.language":{"query":""}}}]}}}`
|
||||
```
|
||||
|
||||
This result is of little surprise to anyone who’s followed the state of open source languages over recent years.
|
||||
|
||||
![Which software languages are the most popular on GitHub.][14]
|
||||
|
||||
[JavaScript][15] is still the reigning champion, and while some believe JavaScript is on its way out, it remains the 800-pound gorilla and is likely to remain that way for some time. [Java][16] faces similar rumors and this data shows that it's a major part of the open source ecosystem.
|
||||
|
||||
Given the popularity of projects like [Docker][17] and [Kubernetes][18], you might be wondering, “What about Go ([Golang][19])?” This is a good time for a reminder that the GitHub dataset discussed here contains some gaps, most significantly after 2017, which is about when I saw Golang projects popping up everywhere. I hope to repeat this search with a complete GitHub dataset and see if it changes the rankings at all.
|
||||
|
||||
Now let's explore the rate of project creation. (Reminder: this is valid JSON consolidated for readability.)
|
||||
|
||||
|
||||
```
|
||||
`{"aggs":{"2":{"date_histogram":{"field":"root.created_at","interval":"1M","time_zone":"America/New_York","min_doc_count":1}}},"size":0,"_source":{"excludes":[]},"stored_fields":["*"],"script_fields":{},"docvalue_fields":["root.created_at","root.updated_at"],"query":{"bool":{"must":[],"filter":[{"match_all":{}}],"should":[],"must_not":[{"match_phrase":{"root.language":{"query":""}}}]}}}`
|
||||
```
|
||||
|
||||
Seeing the rate at which new projects are created would be fun impressive as well, with tremendous growth starting around 2012:
|
||||
|
||||
![The rate at which new projects are created on GitHub.][20]
|
||||
|
||||
Now that I knew the rate of projects created as well as the most popular languages used to create these projects, I wanted to find out what open source licenses these projects chose. Unfortunately, this data doesn’t exist in the GitHub projects dataset, but the fantastic team over at [Tidelift][21] publishes a detailed list of GitHub projects, licenses used, and other details regarding the state of open source software in their [Libraries.io][22][ data][23]. Ingesting this dataset into **CHAOS** SEARCH took just minutes, letting me see which open source software licenses are the most popular on GitHub:
|
||||
|
||||
(Reminder: this is valid JSON consolidated for readability.)
|
||||
|
||||
|
||||
```
|
||||
`{"aggs":{"2":{"terms":{"field":"Repository License","size":10,"order":{"_count":"desc"}}}},"size":0,"_source":{"excludes":[]},"stored_fields":["*"],"script_fields":{},"docvalue_fields":["Created Timestamp","Last synced Timestamp","Latest Release Publish Timestamp","Updated Timestamp"],"query":{"bool":{"must":[],"filter":[{"match_all":{}}],"should":[],"must_not":[{"match_phrase":{"Repository License":{"query":""}}}]}}}`
|
||||
```
|
||||
|
||||
The results show some significant outliers:
|
||||
|
||||
![Which open source software licenses are the most popular on GitHub.][24]
|
||||
|
||||
As you can see, the [MIT license][25] and the [Apache 2.0 license][26] by far outweighs most of the other open source licenses used for these projects, while [various BSD and GPL licenses][27] follow far behind. I can’t say that I’m surprised by these results given GitHub’s open model. I would guess that users, not companies, create most projects and that they use the MIT license to make it simple for other people to use, share, and contribute. That Apache 2.0** **licensing is right behind also makes sense, given just how many companies want to ensure their trademarks are respected and have an open source component to their businesses.
|
||||
|
||||
Now that I identified the most popular licenses, I was curious to see the least used ones. By adjusting my last query, I reversed the top 10 into the bottom 10 and was able to find just two projects using the [University of Illinois—NCSA Open Source License][28]. I had never heard of this license before, but it’s pretty close to Apache 2.0. It’s interesting to see just how many different software licenses are in use across all GitHub projects.
|
||||
|
||||
![The University of Illinois/NCSA open source license.][29]
|
||||
|
||||
The University of Illinois/NCSA open source license.
|
||||
|
||||
After that, I dove into a specific language (JavaScript) to see the most popular license used there. (Reminder: this is valid JSON consolidated for readability.)
|
||||
|
||||
|
||||
```
|
||||
`{"aggs":{"2":{"terms":{"field":"Repository License","size":10,"order":{"_count":"desc"}}}},"size":0,"_source":{"excludes":[]},"stored_fields":["*"],"script_fields":{},"docvalue_fields":["Created Timestamp","Last synced Timestamp","Latest Release Publish Timestamp","Updated Timestamp"],"query":{"bool":{"must":[{"match_phrase":{"Repository Language":{"query":"JavaScript"}}}],"filter":[{"match_all":{}}],"should":[],"must_not":[{"match_phrase":{"Repository License":{"query":""}}}]}}}`
|
||||
```
|
||||
|
||||
There were some surprises in this output.
|
||||
|
||||
![The most popular open source licenses used for GitHub JavaScript projects.][30]
|
||||
|
||||
Even though the default license for [NPM][31] modules when created with **npm init **is the one from [Internet Systems Consortium (ISC)][32], you can see that a considerable number of these projects use MIT as well as Apache 2.0 for their open source license.
|
||||
|
||||
Since the Libraries.io dataset is rich in open source project content, and since the GHTorrent data is missing the last few years’ data (and thus missing any details about Golang projects), I decided to run a similar query to see how Golang projects license their code.
|
||||
|
||||
(Reminder: this is valid JSON consolidated for readability.)
|
||||
|
||||
|
||||
```
|
||||
`{"aggs":{"2":{"terms":{"field":"Repository License","size":10,"order":{"_count":"desc"}}}},"size":0,"_source":{"excludes":[]},"stored_fields":["*"],"script_fields":{},"docvalue_fields":["Created Timestamp","Last synced Timestamp","Latest Release Publish Timestamp","Updated Timestamp"],"query":{"bool":{"must":[{"match_phrase":{"Repository Language":{"query":"Go"}}}],"filter":[{"match_all":{}}],"should":[],"must_not":[{"match_phrase":{"Repository License":{"query":""}}}]}}}`
|
||||
```
|
||||
|
||||
The results were quite different than Javascript.
|
||||
|
||||
![How Golang projects license their GitHub code.][33]
|
||||
|
||||
Golang offers a stunning reversal from JavaScript—nearly three times as many Golang projects are licensed with Apache 2.0 over MIT. While it’s hard precisely explain why this is the case, over the last few years there’s been massive growth in Golang, especially among companies building projects and software offerings, both open source and commercially.
|
||||
|
||||
As we learned above, many of these companies want to enforce their trademarks, thus the move to the Apache 2.0 license makes sense.
|
||||
|
||||
#### Conclusion
|
||||
|
||||
In the end, I found some interesting results by diving into the GitHub users and projects data dump. Some of these I definitely would have guessed, but a few results were surprises to me as well, especially the outliers like the rarely-used NCSA license.
|
||||
|
||||
All in all, you can see how quickly and easily the **CHAOS** SEARCH platform lets us find complicated answers to interesting questions. I dove into this dataset and received deep analytics without having to run any databases myself, and even stored the data inexpensively on Amazon S3—so there’s little maintenance involved. Now I can ask any other questions regarding the data anytime I want.
|
||||
|
||||
What other questions are you asking your data, and what data sets do you use? Let me know in the comments or on Twitter [@petecheslock][34].
|
||||
|
||||
_A version of this article was originally posted on[ **CHAOS** SEARCH][35]._
|
||||
|
||||
* * *
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/5/chaossearch-github-ghtorrent
|
||||
|
||||
作者:[Pete Cheslock][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/petecheslock/users/ghaff/users/payalsingh/users/davidmstokes
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/search_find_code_issue_bug_programming.png?itok=XPrh7fa0 (magnifying glass on computer screen)
|
||||
[2]: https://chaossearch.io/
|
||||
[3]: https://aws.amazon.com/s3/
|
||||
[4]: https://www.elastic.co/
|
||||
[5]: https://www.elastic.co/products/kibana
|
||||
[6]: http://ghtorrent.org
|
||||
[7]: http://ghtorrent.org/services.html
|
||||
[8]: http://ghtorrent.org/downloads.html
|
||||
[9]: http://ndjson.org
|
||||
[10]: https://en.wikipedia.org/wiki/Comma-separated_values
|
||||
[11]: https://en.wikipedia.org/wiki/MySQL
|
||||
[12]: https://www.mongodb.com/
|
||||
[13]: https://stedolan.github.io/jq/
|
||||
[14]: https://opensource.com/sites/default/files/uploads/github-1_500.png (Which software languages are the most popular on GitHub.)
|
||||
[15]: https://en.wikipedia.org/wiki/JavaScript
|
||||
[16]: /resources/java
|
||||
[17]: /resources/what-docker
|
||||
[18]: /resources/what-is-kubernetes
|
||||
[19]: https://golang.org/
|
||||
[20]: https://opensource.com/sites/default/files/uploads/github-2_500.png (The rate at which new projects are created on GitHub.)
|
||||
[21]: https://tidelift.com
|
||||
[22]: http://libraries.io/
|
||||
[23]: https://libraries.io/data
|
||||
[24]: https://opensource.com/sites/default/files/uploads/github-3_500.png (Which open source software licenses are the most popular on GitHub.)
|
||||
[25]: https://opensource.org/licenses/MIT
|
||||
[26]: https://opensource.org/licenses/Apache-2.0
|
||||
[27]: https://opensource.org/licenses
|
||||
[28]: https://tldrlegal.com/license/university-of-illinois---ncsa-open-source-license-(ncsa)
|
||||
[29]: https://opensource.com/sites/default/files/uploads/github-4_500_0.png (The University of Illinois/NCSA open source license.)
|
||||
[30]: https://opensource.com/sites/default/files/uploads/github-5_500_0.png (The most popular open source licenses used for GitHub JavaScript projects.)
|
||||
[31]: https://www.npmjs.com/
|
||||
[32]: https://en.wikipedia.org/wiki/ISC_license
|
||||
[33]: https://opensource.com/sites/default/files/uploads/github-6_500.png (How Golang projects license their GitHub code.)
|
||||
[34]: https://twitter.com/petecheslock
|
||||
[35]: https://chaossearch.io/blog/where-are-the-github-users-part-1/
|
@ -0,0 +1,353 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (cycoe)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Using Pygame to move your game character around)
|
||||
[#]: via: (https://opensource.com/article/17/12/game-python-moving-player)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
用 Pygame 使你的游戏角色移动起来
|
||||
======
|
||||
在本系列的第四部分,学习如何编写移动游戏角色的控制代码。
|
||||

|
||||
|
||||
在这个系列的第一篇文章中,我解释了如何使用 Python 创建一个简单的[基于文本的骰子游戏][1]。在第二部分中,我向你们展示了如何从头开始构建游戏,即从 [创建游戏的环境][2] 开始。然后在第三部分,我们[创建了一个玩家妖精][3],并且使它在你的(而不是空的)游戏世界内生成。你可能已经注意到,如果你不能移动你的角色,那么游戏不是那么有趣。在本篇文章中,我们将使用 Pygame 来添加键盘控制,如此一来你就可以控制你的角色的移动。
|
||||
|
||||
在 Pygame 中有许多函数可以用来添加(除键盘外的)其他控制,但如果你正在敲击 Python 代码,那么你一定是有一个键盘的,这将成为我们接下来会使用的控制方式。一旦你理解了键盘控制,你可以自己去探索其他选项。
|
||||
|
||||
在本系列的第二篇文章中,你已经为退出游戏创建了一个按键,移动角色的(按键)原则也是相同的。但是,使你的角色移动起来要稍微复杂一点。
|
||||
|
||||
让我们从简单的部分入手:设置控制器按键
|
||||
|
||||
### 为控制你的玩家妖精设置按键
|
||||
|
||||
在 IDLE、Ninja-IDE 或文本编辑器中打开你的 Python 游戏脚本。
|
||||
|
||||
因为游戏需要时刻“监听”键盘事件,所以你写的代码需要连续运行。你知道应该把需要在游戏周期中持续运行的代码放在哪里吗?
|
||||
|
||||
如果你回答“放在主循环中”,那么你是正确的!记住除非代码在循环中,否则(大多数情况下)它只会运行仅一次。如果它被写在一个从未被使用的类或函数中,它可能根本不会运行。
|
||||
|
||||
要使 Python 监听传入的按键,将如下代码添加到主循环。目前的代码还不能产生任何的效果,所以使用 `print` 语句来表示成功的信号。这是一种常见的调试技术。
|
||||
|
||||
```
|
||||
while main == True:
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
pygame.quit(); sys.exit()
|
||||
main = False
|
||||
|
||||
if event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_LEFT or event.key == ord('a'):
|
||||
print('left')
|
||||
if event.key == pygame.K_RIGHT or event.key == ord('d'):
|
||||
print('right')
|
||||
if event.key == pygame.K_UP or event.key == ord('w'):
|
||||
print('jump')
|
||||
|
||||
if event.type == pygame.KEYUP:
|
||||
if event.key == pygame.K_LEFT or event.key == ord('a'):
|
||||
print('left stop')
|
||||
if event.key == pygame.K_RIGHT or event.key == ord('d'):
|
||||
print('right stop')
|
||||
if event.key == ord('q'):
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
main = False
|
||||
```
|
||||
|
||||
一些人偏好使用键盘字母 W、A、S 和 D 来控制玩家角色,而另一些偏好使用方向键。因此确保你包含了两种选项。
|
||||
|
||||
**注意:**当你在编程时,同时考虑所有用户是非常重要的。如果你写代码只是为了自己运行,那么很可能你会成为你写的程序的唯一用户。更重要的是,如果你想找一个通过写代码赚钱的工作,你写的代码就应该让所有人都能运行。给你的用户选择权,比如提供使用方向键或 WASD 的选项,是一个优秀程序员的标志。
|
||||
|
||||
使用 Python 启动你的游戏,并在你按下“上下左右”方向键或 A、D 和 W 键的时候查看控制台窗口的输出。
|
||||
|
||||
```
|
||||
$ python ./your-name_game.py
|
||||
left
|
||||
left stop
|
||||
right
|
||||
right stop
|
||||
jump
|
||||
```
|
||||
|
||||
这验证了 Pygame 可以正确地检测按键。现在是时候来完成使妖精移动的艰巨任务了。
|
||||
|
||||
### 编写玩家移动函数
|
||||
|
||||
为了使你的妖精移动起来,你必须为你的妖精创建一个属性代表移动。当你的妖精没有在移动时,这个变量被设为 `0`。
|
||||
|
||||
如果你正在为你的妖精设置动画,或者你决定在将来为他设置动画,你还必须跟踪帧来使走路循环保持在轨迹上。
|
||||
|
||||
在 Player 类中创建如下变量。开头两行作为上下文对照(如果你一直跟着做,你的代码中就已经有这两行),因此只需要添加最后三行:
|
||||
|
||||
```
|
||||
def __init__(self):
|
||||
pygame.sprite.Sprite.__init__(self)
|
||||
self.movex = 0 # 沿 X 方向移动
|
||||
self.movey = 0 # 沿 Y 方向移动
|
||||
self.frame = 0 # 帧计数
|
||||
```
|
||||
|
||||
设置好了这些变量,是时候去为妖精移动编写代码了。
|
||||
|
||||
玩家妖精不需要时刻响应控制,优势它并没有在移动。控制妖精的代码,仅仅只是玩家妖精所有能做的事情中的一小部分。在 Python 中,当你想要使一个对象做某件事并独立于剩余其他代码时,你可以将你的新代码放入一个函数。Python 的函数以关键词 `def` 开头,(该关键词)代表了定义函数。
|
||||
|
||||
在你的 Player 类中创建如下函数,来为你的妖精在屏幕上的位置增加几个像素。现在先不要担心你增加几个像素,这将在后续的代码中确定。
|
||||
|
||||
```
|
||||
def control(self,x,y):
|
||||
'''
|
||||
控制玩家移动
|
||||
'''
|
||||
self.movex += x
|
||||
self.movey += y
|
||||
```
|
||||
|
||||
为了在 Pygame 中移动妖精,你需要告诉 Python 在新的位置重绘妖精,以及这个新位置在哪里。
|
||||
|
||||
因为玩家妖精并不总是在移动,所以更新只需要是 Player 类中的一个函数。将此函数添加前面创建的 `control` 函数之后。
|
||||
|
||||
要使妖精看起来像是在行走(或者飞行,或是你的妖精应该做的任何事),你需要在按下适当的键时改变它在屏幕上的位置。要让它在屏幕上移动,你需要将它的位置(由 `self.rect.x` 和 `self.rect.y` 属性指定)重新定义为当前位置加上已应用的任意 `movex` 或 `movey`。(移动的像素数量将在后续进行设置。)
|
||||
|
||||
```
|
||||
def update(self):
|
||||
'''
|
||||
更新妖精位置
|
||||
'''
|
||||
self.rect.x = self.rect.x + self.movex
|
||||
```
|
||||
|
||||
对 Y 方向做同样的处理:
|
||||
|
||||
```
|
||||
self.rect.y = self.rect.y + self.movey
|
||||
```
|
||||
|
||||
对于动画,在妖精移动时推进动画帧,并使用相应的动画帧作为玩家的图像:
|
||||
|
||||
```
|
||||
# 向左移动
|
||||
if self.movex < 0:
|
||||
self.frame += 1
|
||||
if self.frame > 3*ani:
|
||||
self.frame = 0
|
||||
self.image = self.images[self.frame//ani]
|
||||
|
||||
# 向右移动
|
||||
if self.movex > 0:
|
||||
self.frame += 1
|
||||
if self.frame > 3*ani:
|
||||
self.frame = 0
|
||||
self.image = self.images[(self.frame//ani)+4]
|
||||
```
|
||||
|
||||
通过设置一个变量来告诉代码为你的妖精位置增加多少像素,然后在触发你的玩家妖精的函数时使用这个变量。
|
||||
|
||||
首先,在你的设置部分创建这个变量。在如下代码中,开头两行是上下文对照,因此只需要在你的脚本中增加第三行代码:
|
||||
|
||||
```
|
||||
player_list = pygame.sprite.Group()
|
||||
player_list.add(player)
|
||||
steps = 10 # 移动多少个像素
|
||||
```
|
||||
|
||||
现在你已经有了适当的函数和变量,使用你的按键来触发函数并将变量传递给你的妖精。
|
||||
|
||||
为此,将主循环中的 `print` 语句替换为玩家妖精的名字(player)、函数(.control)以及你希望玩家妖精在每个循环中沿 X 轴和 Y 轴移动的步数。
|
||||
|
||||
```
|
||||
if event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_LEFT or event.key == ord('a'):
|
||||
player.control(-steps,0)
|
||||
if event.key == pygame.K_RIGHT or event.key == ord('d'):
|
||||
player.control(steps,0)
|
||||
if event.key == pygame.K_UP or event.key == ord('w'):
|
||||
print('jump')
|
||||
|
||||
if event.type == pygame.KEYUP:
|
||||
if event.key == pygame.K_LEFT or event.key == ord('a'):
|
||||
player.control(steps,0)
|
||||
if event.key == pygame.K_RIGHT or event.key == ord('d'):
|
||||
player.control(-steps,0)
|
||||
if event.key == ord('q'):
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
main = False
|
||||
```
|
||||
|
||||
记住,`steps` 变量代表了当一个按键被按下时,你的妖精会移动多少个像素。如果当你按下 D 或右方向键时,你的妖精的位置增加了 10 个像素。那么当你停止按下这个键时,你必须(将 `step`)减 10(`-steps`)来使你的妖精的动量回到 0。
|
||||
|
||||
现在尝试你的游戏。注意:它不会像你预想的那样运行。
|
||||
|
||||
为什么你的妖精仍无法移动?因为主循环还没有调用 `update` 函数。
|
||||
|
||||
将如下代码加入到你的主循环中来告诉 Python 更新你的玩家妖精的位置。增加带注释的那行:
|
||||
|
||||
```
|
||||
player.update() # 更新玩家位置
|
||||
player_list.draw(world)
|
||||
pygame.display.flip()
|
||||
clock.tick(fps)
|
||||
```
|
||||
|
||||
再次启动你的游戏来见证你的玩家妖精在你的命令下在屏幕上来回移动。现在还没有垂直方向的移动,因为这部分函数会被重力控制,不过这是另一篇文章中的课程了。
|
||||
|
||||
与此同时,如果你拥有一个摇杆,你可以尝试阅读 Pygame 中 [joystick][4] 模块相关的文档,看看你是否能通过这种方式让你的妖精移动起来。或者,看看你是否能通过[鼠标][5]与你的妖精互动。
|
||||
|
||||
最重要的是,玩的开心!
|
||||
|
||||
### 本教程中用到的所有代码
|
||||
|
||||
为了方便查阅,以下是目前本系列文章用到的所有代码。
|
||||
|
||||
```
|
||||
#!/usr/bin/env python3
|
||||
# 绘制世界
|
||||
# 添加玩家和玩家控制
|
||||
# 添加玩家移动控制
|
||||
|
||||
# GNU All-Permissive License
|
||||
# Copying and distribution of this file, with or without modification,
|
||||
# are permitted in any medium without royalty provided the copyright
|
||||
# notice and this notice are preserved. This file is offered as-is,
|
||||
# without any warranty.
|
||||
|
||||
import pygame
|
||||
import sys
|
||||
import os
|
||||
|
||||
'''
|
||||
Objects
|
||||
'''
|
||||
|
||||
class Player(pygame.sprite.Sprite):
|
||||
'''
|
||||
生成玩家
|
||||
'''
|
||||
def __init__(self):
|
||||
pygame.sprite.Sprite.__init__(self)
|
||||
self.movex = 0
|
||||
self.movey = 0
|
||||
self.frame = 0
|
||||
self.images = []
|
||||
for i in range(1,5):
|
||||
img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
|
||||
img.convert_alpha()
|
||||
img.set_colorkey(ALPHA)
|
||||
self.images.append(img)
|
||||
self.image = self.images[0]
|
||||
self.rect = self.image.get_rect()
|
||||
|
||||
def control(self,x,y):
|
||||
'''
|
||||
控制玩家移动
|
||||
'''
|
||||
self.movex += x
|
||||
self.movey += y
|
||||
|
||||
def update(self):
|
||||
'''
|
||||
更新妖精位置
|
||||
'''
|
||||
|
||||
self.rect.x = self.rect.x + self.movex
|
||||
self.rect.y = self.rect.y + self.movey
|
||||
|
||||
# 向左移动
|
||||
if self.movex < 0:
|
||||
self.frame += 1
|
||||
if self.frame > 3*ani:
|
||||
self.frame = 0
|
||||
self.image = self.images[self.frame//ani]
|
||||
|
||||
# 向右移动
|
||||
if self.movex > 0:
|
||||
self.frame += 1
|
||||
if self.frame > 3*ani:
|
||||
self.frame = 0
|
||||
self.image = self.images[(self.frame//ani)+4]
|
||||
|
||||
|
||||
'''
|
||||
设置
|
||||
'''
|
||||
worldx = 960
|
||||
worldy = 720
|
||||
|
||||
fps = 40 # 帧刷新率
|
||||
ani = 4 # 动画循环
|
||||
clock = pygame.time.Clock()
|
||||
pygame.init()
|
||||
main = True
|
||||
|
||||
BLUE = (25,25,200)
|
||||
BLACK = (23,23,23 )
|
||||
WHITE = (254,254,254)
|
||||
ALPHA = (0,255,0)
|
||||
|
||||
world = pygame.display.set_mode([worldx,worldy])
|
||||
backdrop = pygame.image.load(os.path.join('images','stage.png')).convert()
|
||||
backdropbox = world.get_rect()
|
||||
player = Player() # 生成玩家
|
||||
player.rect.x = 0
|
||||
player.rect.y = 0
|
||||
player_list = pygame.sprite.Group()
|
||||
player_list.add(player)
|
||||
steps = 10 # 移动速度
|
||||
|
||||
'''
|
||||
主循环
|
||||
'''
|
||||
while main == True:
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
pygame.quit(); sys.exit()
|
||||
main = False
|
||||
|
||||
if event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_LEFT or event.key == ord('a'):
|
||||
player.control(-steps,0)
|
||||
if event.key == pygame.K_RIGHT or event.key == ord('d'):
|
||||
player.control(steps,0)
|
||||
if event.key == pygame.K_UP or event.key == ord('w'):
|
||||
print('jump')
|
||||
|
||||
if event.type == pygame.KEYUP:
|
||||
if event.key == pygame.K_LEFT or event.key == ord('a'):
|
||||
player.control(steps,0)
|
||||
if event.key == pygame.K_RIGHT or event.key == ord('d'):
|
||||
player.control(-steps,0)
|
||||
if event.key == ord('q'):
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
main = False
|
||||
|
||||
# world.fill(BLACK)
|
||||
world.blit(backdrop, backdropbox)
|
||||
player.update()
|
||||
player_list.draw(world) # 更新玩家位置
|
||||
pygame.display.flip()
|
||||
clock.tick(fps)
|
||||
```
|
||||
|
||||
你已经学了很多,但还仍有许多可以做。在接下来的几篇文章中,你将实现添加敌方妖精、模拟重力等等。与此同时,练习 Python 吧!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/17/12/game-python-moving-player
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[cycoe](https://github.com/cycoe)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/article/17/10/python-101
|
||||
[2]: https://opensource.com/article/17/12/program-game-python-part-2-creating-game-world
|
||||
[3]: https://opensource.com/article/17/12/program-game-python-part-3-spawning-player
|
||||
[4]: http://pygame.org/docs/ref/joystick.html
|
||||
[5]: http://pygame.org/docs/ref/mouse.html#module-pygame.mouse
|
@ -0,0 +1,60 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Get started with Libki to manage public user computer access)
|
||||
[#]: via: (https://opensource.com/article/19/5/libki-computer-access)
|
||||
[#]: author: (Don Watkins https://opensource.com/users/don-watkins/users/tony-thomas)
|
||||
|
||||
开始使用 Libk i来管理公共用户访问计算机
|
||||
======
|
||||
Libki 是一个跨平台的计算机预约和时间管理系统。
|
||||
![][1]
|
||||
|
||||
提供公共计算机的图书馆、学校、学院和其他组织需要一种管理用户访问权限的好方法 - 否则,就无法阻止某些人独占机器并确保每个人都有公平的时间。这是 [Libki][2] 要解决的问题。
|
||||
|
||||
Libki 是一个面向 Windows 和 Linux PC 的开源、跨平台的计算机预约和时间管理系统。它提供了一个基于 Web 的服务器和一个基于 Web 的管理系统,员工可以使用它来管理计算机访问,包括创建和删除用户、设置帐户时间限制、登出和禁止用户以及设置访问限制。
|
||||
|
||||
根据首席开发人员 [Kyle Hall][3] 所说,Libki 主要用于 PC 时间控制,作为 Envisionware 的专有计算机访问控制软件的开源替代品。当用户登录 Libki 管理的计算机时,他们会有一段时间来使用计算机。时间到了之后,他们就会被登出。时间默认设置为 45 分钟,但可以使用基于 Web 的管理系统轻松调整。一些组织在登出用户之前提供 24 小时访问权限,而有的组织则使用它来跟踪使用情况而不设置时间限制。
|
||||
|
||||
Kyle 目前是 [ByWater Solutions][4] 的首席开发人员,该公司为图书馆提供开源软件解决方案(包括 Libki)。在职业生涯早期,他在宾夕法尼亚州的[米德维尔公共图书馆][5]担任 IT 技术时开发了 Libki。在其他员工的午休期间,偶尔会要求他关注孩子的房间。图书馆使用纸质注册表来管理对儿童房间计算机的访问,这意味着不断的监督和检查,以确保来到那里的人能够公平地使用。
|
||||
|
||||
Kyle 说,“我发现这个系统很麻烦、很尴尬,我想找到一个解决方案。这个解决方案需要同时是 FOSS 和跨平台的。最后,没有现有的软件适合我们的特殊需求,那就是为什么我开发了 Libki。“
|
||||
|
||||
或者,正如 Libki 的网站所宣称的那样,“Libki 的诞生是为了避免与青少年互动,现在允许图书馆员避免与世界各地的青少年互动!”
|
||||
|
||||
### 易于安装和使用
|
||||
|
||||
我最近决定在我经常在那里做志愿者的当地的公共图书馆尝试 Libki。我按照[文档][6]在 Ubuntu 18.04 Server 中自动进行了安装,它很快就启动起来了。
|
||||
|
||||
我计划在我们当地的图书馆支持 Libki,但我想知道在那些没有 IT 相关经验的人或者无法构建和部署服务器的图书馆是怎样的。Kyle 说:“ByWater Solutions 可以云端托管 Libki 服务器,这使得每个人的维护和管理变得更加简单。”
|
||||
|
||||
Kyle 表示,ByWater 并不打算将 Libki 与其最受欢迎的产品,开源集成图书馆系统 (ILS)Koha 或其支持的任何其他[项目][7]捆绑在一起。他说: “Libki 和 Koha 是不同[类型]的软件,满足不同的需求,但它们在图书馆中确实很好地协同工作。事实上,我很早就开发了 Libki 的 SIP2 集成,因此它可以支持使用 Koha 进行单点登录,“ 。
|
||||
|
||||
### 如何贡献
|
||||
|
||||
Libki 客户端是 GPLv3 许可,Libki 服务器是 AGPLv3 许可。Kyle 说他希望 Libki 拥有一个更加活跃和强大的社区,项目一直在寻找新人加入其[贡献者][8]。如果你想参加,请访问 [Libki 社区页面][9]并加入邮件列表。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/5/libki-computer-access
|
||||
|
||||
作者:[Don Watkins ][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/don-watkins/users/tony-thomas
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/desk_clock_job_work.jpg?itok=Nj4fuhl6
|
||||
[2]: https://libki.org/
|
||||
[3]: https://www.linkedin.com/in/kylemhallinfo/
|
||||
[4]: https://opensource.com/article/19/4/software-libraries
|
||||
[5]: https://meadvillelibrary.org/
|
||||
[6]: https://manual.libki.org/master/libki-manual.html#_automatic_installation
|
||||
[7]: https://bywatersolutions.com/projects
|
||||
[8]: https://github.com/Libki/libki-server/graphs/contributors
|
||||
[9]: https://libki.org/community/
|
@ -1,140 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (warmfrog)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to use advanced rsync for large Linux backups)
|
||||
[#]: via: (https://opensource.com/article/19/5/advanced-rsync)
|
||||
[#]: author: (Alan Formy-Duval https://opensource.com/users/alanfdoss/users/marcobravo)
|
||||
|
||||
如何使用高级工具 rsync 进行大的 Linux 备份
|
||||
=====================================
|
||||
基础的 rsync 命令通常足够来管理你的 Linux 备份,但是额外的选项使大数据集备份更快更强大。
|
||||
![Filing papers and documents][1]
|
||||
|
||||
很明显,备份一直是Linux世界的热门话题。回到 2017,David Both 为 [Opensource.com][2] 的读者在"[使用 rsync 备份你的 Linux 系统][3]方面提了一些建议,在这年的更早时候,他发起了一项问卷调查询问大家,"[在 Linux 中你的 /home 目录的主要备份策略是什么][4]",在今年的另一个问卷调查中,Don Watkins 问到,"[你使用哪种开源备份解决方案][5]"。
|
||||
|
||||
我的回复是 [rsync][6]。市场上有大量大的复杂的工具,对于管理磁带机或者存储库设备,这些可能是必要的,但是可能你需要的只是一个简单的开源命令行工具。
|
||||
|
||||
### rsync 基础
|
||||
|
||||
我为一个大概拥有 35,000 开发者并有着几十 TB 文件的全球组织管理二进制仓库。我经常一次移动或者归档上百 GB 的数据。使用的是 rsync。这种经历使我对这个简单的工具充满信心。(所以,是的,我在家使用它来备份我的 Linux 系统)
|
||||
|
||||
基础的 rsync 命令很简单。
|
||||
|
||||
|
||||
```
|
||||
`rsync -av 源目录 目的地目录`
|
||||
```
|
||||
|
||||
实际上,在任何指南中教的 rsync 命令在大多数通用情况下都运行的很好。然而,假设我们需要备份大量的数据。例如包含 2,000 个子目录的目录,每个包含 50GB 到 700GB 的数据。在这个目录运行 rsync 可能需要大量时间,尤其是当你使用 checksum 选项时(我倾向使用的)。
|
||||
|
||||
当我们试图同步大量数据或者通过慢的网络连接时,可能遇到性能问题。让我给你展示一些我使用的方法来确保好的性能和可靠性。
|
||||
|
||||
### 高级 rsync
|
||||
|
||||
当 rsync 运行时出现的第一行是:“正在发送增量文件列表。” 如果你搜索这一行,你将看到很多类似的问题:为什么它一直运行,或者为什么它似乎挂起了。
|
||||
|
||||
这里是一个基于这个场景的例子。假设我们有一个 **/storage** 的目录,我们想要备份到一个外部 USB 磁盘,我们可以使用下面的命令:
|
||||
|
||||
|
||||
```
|
||||
`rsync -cav /storage /media/WDPassport`
|
||||
```
|
||||
|
||||
**c** 选项告诉 rsync 使用文件校验和而不是时间戳来决定改变的文件,这通常消耗的时间更久。为了分解 **/storage** 目录,我通过子目录同步,使用 **find** 命令。这是一个例子:
|
||||
|
||||
|
||||
```
|
||||
`find /storage -type d -exec rsync -cav {} /media/WDPassport \;`
|
||||
```
|
||||
|
||||
这看起来可以,但是如果 **/storage** 目录有任何文件,它们将被跳过。因此,我们如何同步 **/storage** 目录中的文件呢?同样有一个细微的差别是具体的选项将造成 rsync 同步 **.** 目录,该目录是源目录自身;这意味着它会同步子目录两次,这并不是我们想要的。
|
||||
|
||||
长话短说,我的解决方案是一个 “双-递增”脚本。这允许我分解一个目录,例如,当你的 home 目录有多个大的目录,例如音乐或者家庭照片时,分解 **/home** 目录为单个的用户 home 目录。
|
||||
|
||||
这是我的脚本的一个例子:
|
||||
|
||||
|
||||
```
|
||||
HOMES="alan"
|
||||
DRIVE="/media/WDPassport"
|
||||
|
||||
for HOME in $HOMES; do
|
||||
cd /home/$HOME
|
||||
rsync -cdlptgov --delete . /$DRIVE/$HOME
|
||||
find . -maxdepth 1 -type d -not -name "." -exec rsync -crlptgov --delete {} /$DRIVE/$HOME \;
|
||||
done
|
||||
```
|
||||
|
||||
第一个 rsync 命令拷贝它在源目录中发现的文件和目录。然而,它将目录留空,因此我们能够通过 **find** 命令迭代他们。这通过传递 **d** 参数来完成,它告诉 rsync 不要递归目录。
|
||||
|
||||
|
||||
```
|
||||
`-d, --dirs transfer directories without recursing`
|
||||
```
|
||||
|
||||
然后 **find** 命令传递每个目录来单独运行 rsync。之后 rsync 拷贝目录的内容。这通过传递 **r** 参数来完成,它告诉 rsync 要递归目录。
|
||||
|
||||
|
||||
```
|
||||
`-r, --recursive 递归进入目录`
|
||||
```
|
||||
|
||||
这使得 rsync使用的增量文件保持在一个可管理的大小。
|
||||
|
||||
大多数 rsync 指南为了简便使用 **a** (或者 **archive**) 参数。这实际是一个复合参数。
|
||||
|
||||
|
||||
```
|
||||
`-a, --archive 归档模式; equals -rlptgoD (no -H,-A,-X)`
|
||||
```
|
||||
|
||||
我传递的其他参数包含在 **a** 中;这些是 **l** , **p** , **t** , **g** , 和 **o**。
|
||||
|
||||
|
||||
```
|
||||
-l, --links 复制符号链接作为符号链接
|
||||
-p, --perms 保留权限
|
||||
-t, --times 保留修改时间
|
||||
-g, --group 保留组
|
||||
-o, --owner 保留拥有者(只适用于超级管理员)
|
||||
```
|
||||
|
||||
**\--delete** 选项告诉 rsync 删除目的地目录中所有在源目录不存在的任意文件。这种方式,运行的结果仅仅是复制。你同样可以排除 **.Trash** 目录或者 MacOS 创建的 **.DS_Store** 文件。
|
||||
|
||||
|
||||
```
|
||||
`-not -name ".Trash*" -not -name ".DS_Store"`
|
||||
```
|
||||
|
||||
### 注意
|
||||
|
||||
最后一条建议: rsync 可以是破坏性的命令。幸运的是,它的睿智的创造者提供了 “空运行”的能力。如果我们加入 **n** 选项,rsync 会显示预期的输出但不写任何数据。
|
||||
|
||||
|
||||
```
|
||||
`rsync -cdlptgovn --delete . /$DRIVE/$HOME`
|
||||
```
|
||||
|
||||
这个脚本适用于非常大的存储规模和高延迟或者慢链接的情况。一如既往,我确信仍有提升的空间。如果你有任何建议,请在下方评论中分享。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/5/advanced-rsync
|
||||
|
||||
作者:[Alan Formy-Duval ][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[warmfrog](https://github.com/warmfrog)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/alanfdoss/users/marcobravo
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/documents_papers_file_storage_work.png?itok=YlXpAqAJ (Filing papers and documents)
|
||||
[2]: http://Opensource.com
|
||||
[3]: https://opensource.com/article/17/1/rsync-backup-linux
|
||||
[4]: https://opensource.com/poll/19/4/backup-strategy-home-directory-linux
|
||||
[5]: https://opensource.com/article/19/2/linux-backup-solutions
|
||||
[6]: https://en.wikipedia.org/wiki/Rsync
|
Loading…
Reference in New Issue
Block a user