mirror of
https://github.com/LCTT/TranslateProject.git
synced 2026-09-04 04:32:49 +08:00
Merge branch 'master' of https://github.com/LCTT/TranslateProject into translating
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (messon007)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
@@ -1,607 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Getting started with the Rust package manager, Cargo)
|
||||
[#]: via: (https://opensource.com/article/20/3/rust-cargo)
|
||||
[#]: author: (Gaurav Kamathe https://opensource.com/users/gkamathe)
|
||||
|
||||
Getting started with the Rust package manager, Cargo
|
||||
======
|
||||
Get to know Rust's package manager and build tool.
|
||||
![Shipping containers stacked in a yard][1]
|
||||
|
||||
[Rust][2] is a modern programming language that provides performance, reliability, and productivity. It has consistently been voted as the [most-loved language][3] on StackOverflow surveys for a few years now.
|
||||
|
||||
In addition to being a great programming language, Rust also features a build system and package manager called Cargo. Cargo handles a lot of tasks, like building code, downloading libraries or dependencies, and so on. The two are bundled together, so you get Cargo when you install Rust.
|
||||
|
||||
### Installing Rust and Cargo
|
||||
|
||||
Before getting started, you need to install Rust and Cargo. The Rust project provides a downloadable script to handle the installation. To get the script, open a browser to [https://sh.rustup.rs][4] and save the file. Read the script to make sure you're happy with what it intends to do, and then run it:
|
||||
|
||||
|
||||
```
|
||||
`$ sh ./rustup.rs`
|
||||
```
|
||||
|
||||
You can also refer to the [Install Rust][5] webpage for more information.
|
||||
|
||||
After installing Rust and Cargo, you must source the env file:
|
||||
|
||||
|
||||
```
|
||||
`$ source $HOME/.cargo/env`
|
||||
```
|
||||
|
||||
Better yet, add the required directory to your PATH variable:
|
||||
|
||||
|
||||
```
|
||||
`$ source $HOME/.cargo/env`
|
||||
```
|
||||
|
||||
If you prefer to use your package manager (such as DNF or Apt on Linux), look for Rust and Cargo packages in your distribution's repositories and install accordingly. For example:
|
||||
|
||||
|
||||
```
|
||||
`$ dnf install rust cargo`
|
||||
```
|
||||
|
||||
Once they're installed and set up, verify which versions of Rust and Cargo you have:
|
||||
|
||||
|
||||
```
|
||||
$ rustc --version
|
||||
rustc 1.41.0 (5e1a79984 2020-01-27)
|
||||
$ cargo --version
|
||||
cargo 1.41.0 (626f0f40e 2019-12-03)
|
||||
```
|
||||
|
||||
### Building and running Rust by hand
|
||||
|
||||
Start with a simple program that prints "Hello, world!" on the screen. Open your favorite text editor and type the following program:
|
||||
|
||||
|
||||
```
|
||||
$ cat hello.rs
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
```
|
||||
|
||||
Save the file with an **.rs** extension to identify it as a Rust source code file.
|
||||
|
||||
Compile your program using the Rust compiler, **rustc**:
|
||||
|
||||
|
||||
```
|
||||
`$ rustc hello.rs`
|
||||
```
|
||||
|
||||
After compilation, you will have a binary that has the same name as the source program:
|
||||
|
||||
|
||||
```
|
||||
$ ls -l
|
||||
total 2592
|
||||
-rwxr-xr-x. 1 user group 2647944 Feb 13 14:14 hello
|
||||
-rw-r--r--. 1 user group 45 Feb 13 14:14 hello.rs
|
||||
$
|
||||
```
|
||||
|
||||
Execute your program to verify that it runs as expected:
|
||||
|
||||
|
||||
```
|
||||
$ ./hello
|
||||
Hello, world!
|
||||
```
|
||||
|
||||
These steps are sufficient for smaller programs or whenever you want to test out something quickly. However, when working on bigger programs involving multiple people, Cargo is the best way forward.
|
||||
|
||||
### Creating a new package using Cargo
|
||||
|
||||
Cargo is a build system and package manager for Rust. It helps developers download and manage dependencies and assists in creating Rust packages. Packages in Rust are often called "crates" in the Rust community, but in this article, the two words are interchangeable. Refer to the Cargo [FAQ][6] provided by the Rust community for clarification.
|
||||
|
||||
If you need any help with Cargo's command-line utility, use the **\--help** or **-h** command-line argument:
|
||||
|
||||
|
||||
```
|
||||
`$ cargo –help`
|
||||
```
|
||||
|
||||
To create a new package, use the **new** keyword, followed by the package name. For this example, use **hello_opensource** as your new package name. After running the command, you will see a message confirming that Cargo has created a binary package with the given name:
|
||||
|
||||
|
||||
```
|
||||
$ cargo new hello_opensource
|
||||
Created binary (application) `hello_opensource` package
|
||||
```
|
||||
|
||||
Running a **tree** command to see the directory structure reports that some files and directories were created. First, it creates a directory with the name of the package, and within that directory is an **src** directory for your source code files:
|
||||
|
||||
|
||||
```
|
||||
$ tree .
|
||||
.
|
||||
└── hello_opensource
|
||||
├── Cargo.toml
|
||||
└── src
|
||||
└── main.rs
|
||||
|
||||
2 directories, 2 files
|
||||
```
|
||||
|
||||
Cargo not only creates a package, but it also creates a simple **Hello, world!** program. Open the **main.rs** file and have a look:
|
||||
|
||||
|
||||
```
|
||||
$ cat hello_opensource/src/main.rs
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
```
|
||||
|
||||
The next file to work with is **Cargo.toml**, which is a configuration file for your package. It contains information about the package, such as its name, version, author information, and Rust edition information.
|
||||
|
||||
A program often depends on external libraries or dependencies to run, which enables you to write applications that perform tasks that you don't know how to code or you don't want to spend time coding. All your dependencies will be listed in this file. At this point, you do not have any dependencies for your new program. Open the **Cargo.toml** file and view its contents:
|
||||
|
||||
|
||||
```
|
||||
$ cat hello_opensource/Cargo.toml
|
||||
[package]
|
||||
name = "hello_opensource"
|
||||
version = "0.1.0"
|
||||
authors = ["user <[user@mail.com][7]>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at <https://doc.rust-lang.org/cargo/reference/manifest.html>
|
||||
|
||||
[dependencies]
|
||||
```
|
||||
|
||||
### Building the program using Cargo
|
||||
|
||||
So far, so good. Now that you have a package in place, build a binary (also called an executable). Before doing that, move into the package directory:
|
||||
|
||||
|
||||
```
|
||||
`$ cd hello_opensource/`
|
||||
```
|
||||
|
||||
You can use Cargo's **build** command to build the package. Notice the messages that say it is **Compiling** your program:
|
||||
|
||||
|
||||
```
|
||||
$ cargo build
|
||||
Compiling hello_opensource v0.1.0 (/opensource/hello_opensource)
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 0.38s
|
||||
```
|
||||
|
||||
Check what happens to your project directory after you run the **build** command:
|
||||
|
||||
|
||||
```
|
||||
$ tree .
|
||||
.
|
||||
├── Cargo.lock
|
||||
├── Cargo.toml
|
||||
├── src
|
||||
│ └── main.rs
|
||||
└── target
|
||||
└── debug
|
||||
├── build
|
||||
├── deps
|
||||
│ ├── hello_opensource-147b8a0f466515dd
|
||||
│ └── hello_opensource-147b8a0f466515dd.d
|
||||
├── examples
|
||||
├── hello_opensource
|
||||
├── hello_opensource.d
|
||||
└── incremental
|
||||
└── hello_opensource-3pouh4i8ttpvz
|
||||
├── s-fkmhjmt8tj-x962ep-1hivstog8wvf
|
||||
│ ├── 1r37g6m45p8rx66m.o
|
||||
│ ├── 2469ykny0eqo592v.o
|
||||
│ ├── 2g5i2x8ie8zed30i.o
|
||||
│ ├── 2yrvd7azhgjog6zy.o
|
||||
│ ├── 3g9rrdr4hyk76jtd.o
|
||||
│ ├── dep-graph.bin
|
||||
│ ├── query-cache.bin
|
||||
│ ├── work-products.bin
|
||||
│ └── wqif2s56aj0qtct.o
|
||||
└── s-fkmhjmt8tj-x962ep.lock
|
||||
|
||||
9 directories, 17 files
|
||||
```
|
||||
|
||||
Wow! The compilations process produced a lot of intermediate files. Your binary, though, is saved in the **./target/debug** directory with the same name as your package.
|
||||
|
||||
### Running your application using Cargo
|
||||
|
||||
Now that your binary is built, run it using Cargo's **run** command. As expected, it prints **Hello, world!** on the screen.
|
||||
|
||||
|
||||
```
|
||||
$ cargo run
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 0.01s
|
||||
Running `target/debug/hello_opensource`
|
||||
Hello, world!
|
||||
```
|
||||
|
||||
Alternatively, you can run the binary directly, which is located at:
|
||||
|
||||
|
||||
```
|
||||
$ ls -l ./target/debug/hello_opensource
|
||||
-rwxr-xr-x. 2 root root 2655552 Feb 13 14:19 ./target/debug/hello_opensource
|
||||
```
|
||||
|
||||
As expected, it produces the same results:
|
||||
|
||||
|
||||
```
|
||||
$ ./target/debug/hello_opensource
|
||||
Hello, world!
|
||||
```
|
||||
|
||||
Say you need to rebuild your package and get rid of all the binaries and the intermediate files created by the earlier compilation process. Cargo provides a handy **clean** option to remove all intermediate files except the source code and other required files:
|
||||
|
||||
|
||||
```
|
||||
$ cargo clean
|
||||
$ tree .
|
||||
.
|
||||
├── Cargo.lock
|
||||
├── Cargo.toml
|
||||
└── src
|
||||
└── main.rs
|
||||
|
||||
1 directory, 3 files
|
||||
```
|
||||
|
||||
Make some changes to the program and run it again to see how it works. For example, this minor change adds **Opensource** to the **Hello, world!** string:
|
||||
|
||||
|
||||
```
|
||||
$ cat src/main.rs
|
||||
fn main() {
|
||||
println!("Hello, Opensource world!");
|
||||
}
|
||||
```
|
||||
|
||||
Now, build the program and run it again. This time you see **Hello, Opensource world!** displayed on the screen:
|
||||
|
||||
|
||||
```
|
||||
$ cargo build
|
||||
Compiling hello_opensource v0.1.0 (/opensource/hello_opensource)
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 0.39s
|
||||
|
||||
$ cargo run
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 0.01s
|
||||
Running `target/debug/hello_opensource`
|
||||
Hello, Opensource world!
|
||||
```
|
||||
|
||||
### Adding dependencies using Cargo
|
||||
|
||||
Cargo allows you to add dependencies that your program needs to run. Adding a dependency is extremely easy with Cargo. Every Rust package includes a **Cargo.toml** file, which contains a list (empty by default) of dependencies. Open the file in your favorite text editor, find the **[dependencies]** section, and add the library you want to include in your package. For example, to add the **rand** library as your dependency:
|
||||
|
||||
|
||||
```
|
||||
$ cat Cargo.toml
|
||||
[package]
|
||||
name = "hello_opensource"
|
||||
version = "0.1.0"
|
||||
authors = ["test user <[test@mail.com][8]>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at <https://doc.rust-lang.org/cargo/reference/manifest.html>
|
||||
|
||||
[dependencies]
|
||||
rand = "0.3.14"
|
||||
```
|
||||
|
||||
Try building your package to see what happens.
|
||||
|
||||
|
||||
```
|
||||
$ cargo build
|
||||
Updating crates.io index
|
||||
Compiling libc v0.2.66
|
||||
Compiling rand v0.4.6
|
||||
Compiling rand v0.3.23
|
||||
Compiling hello_opensource v0.1.0 (/opensource/hello_opensource)
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 4.48s
|
||||
```
|
||||
|
||||
Cargo is now reaching out to [Crates.io][9], which is Rust's central repository for crates (or packages) and downloading and compiling **rand**. But wait—what about the **libc** package? You did not ask for **libc** to be installed. Well, the **rand** package is dependent on the **libc** package; hence, Cargo downloads and compiles **libc** as well.
|
||||
|
||||
New versions of libraries keep coming, and Cargo provides an easy way to update all of their dependencies using the **update** command:
|
||||
|
||||
|
||||
```
|
||||
`cargo update`
|
||||
```
|
||||
|
||||
You can also choose to update specific libraries using the **-p** flag followed by the package name:
|
||||
|
||||
|
||||
```
|
||||
`cargo update -p rand`
|
||||
```
|
||||
|
||||
### Compiling and running with a single command
|
||||
|
||||
So far, you have used **build** followed by **run** whenever you make changes to your program. There is an easier way: you can simply use the **run** command, which internally compiles and runs the program. To see how it works, first clean up your package directory:
|
||||
|
||||
|
||||
```
|
||||
$ cargo clean
|
||||
$ tree .
|
||||
.
|
||||
├── Cargo.lock
|
||||
├── Cargo.toml
|
||||
└── src
|
||||
└── main.rs
|
||||
|
||||
1 directory, 3 files
|
||||
```
|
||||
|
||||
Now execute **run**. The output states that it compiled and then ran the program, and this means you don't need to explicitly run **build** each time:
|
||||
|
||||
|
||||
```
|
||||
$ cargo run
|
||||
Compiling hello_opensource v0.1.0 (/opensource/hello_opensource)
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 0.41s
|
||||
Running `target/debug/hello_opensource`
|
||||
Hello, world!
|
||||
```
|
||||
|
||||
### Checking your code in development
|
||||
|
||||
You often go through multiple iterations when developing a program. You need to ensure that your program has no coding errors and compiles fine. You don't need the overhead of generating the binary on each compilation. Cargo has you covered with a **check** option that compiles your code but skips the final step of generating an executable.
|
||||
|
||||
Start by running **cargo clean** within your package directory:
|
||||
|
||||
|
||||
```
|
||||
$ tree .
|
||||
.
|
||||
├── Cargo.lock
|
||||
├── Cargo.toml
|
||||
└── src
|
||||
└── main.rs
|
||||
|
||||
1 directory, 3 files
|
||||
```
|
||||
|
||||
Now run the **check** command and see what changes were made to the directory:
|
||||
|
||||
|
||||
```
|
||||
$ cargo check
|
||||
Checking hello_opensource v0.1.0 (/opensource/hello_opensource)
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 0.18s
|
||||
```
|
||||
|
||||
The output shows that, even though intermediate files were created as part of the compilation process, the final binary or executable was not created. This saves some time, which matters a lot if the package is huge with thousands of lines of code:
|
||||
|
||||
|
||||
```
|
||||
$ tree .
|
||||
.
|
||||
├── Cargo.lock
|
||||
├── Cargo.toml
|
||||
├── src
|
||||
│ └── main.rs
|
||||
└── target
|
||||
└── debug
|
||||
├── build
|
||||
├── deps
|
||||
│ ├── hello_opensource-842d9a06b2b6a19b.d
|
||||
│ └── libhello_opensource-842d9a06b2b6a19b.rmeta
|
||||
├── examples
|
||||
└── incremental
|
||||
└── hello_opensource-1m3f8arxhgo1u
|
||||
├── s-fkmhw18fjk-542o8d-18nukzzq7hpxe
|
||||
│ ├── dep-graph.bin
|
||||
│ ├── query-cache.bin
|
||||
│ └── work-products.bin
|
||||
└── s-fkmhw18fjk-542o8d.lock
|
||||
|
||||
9 directories, 9 files
|
||||
```
|
||||
|
||||
To see if you are really saving time, time the **build** and **check** commands and compare them.
|
||||
|
||||
First, the **build** command:
|
||||
|
||||
|
||||
```
|
||||
$ time cargo build
|
||||
Compiling hello_opensource v0.1.0 (/opensource/hello_opensource)
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 0.40s
|
||||
|
||||
real 0m0.416s
|
||||
user 0m0.251s
|
||||
sys 0m0.199s
|
||||
```
|
||||
|
||||
Clean the directory before running the **check** command:
|
||||
|
||||
|
||||
```
|
||||
`$ cargo clean`
|
||||
```
|
||||
|
||||
The **check** command:
|
||||
|
||||
|
||||
```
|
||||
$ time cargo check
|
||||
Checking hello_opensource v0.1.0 (/opensource/hello_opensource)
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 0.15s
|
||||
|
||||
real 0m0.166s
|
||||
user 0m0.086s
|
||||
sys 0m0.081s
|
||||
```
|
||||
|
||||
Clearly, the **check** command is much faster.
|
||||
|
||||
### Building external Rust packages
|
||||
|
||||
Everything you've done so far will apply to any Rust crate you get from the internet. You simply need to download or clone the repository, move to the package folder, and run the **build** command, and you are good to go:
|
||||
|
||||
|
||||
```
|
||||
git clone <github-like-url>
|
||||
cd <package-folder>
|
||||
cargo build
|
||||
```
|
||||
|
||||
### Building optimized Rust programs using Cargo
|
||||
|
||||
You've run **build** multiple times so far, but did you notice its output? No worries, build it again and watch closely:
|
||||
|
||||
|
||||
```
|
||||
$ cargo build
|
||||
Compiling hello_opensource v0.1.0 (/opensource/hello_opensource)
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 0.36s
|
||||
```
|
||||
|
||||
See the **[unoptimized + debuginfo]** text after each compilation? This means that the binary generated by Cargo includes a lot of debugging information and is not optimized for execution. Developers often go through multiple iterations of development and need this debugging information for analysis. Also, performance is not the immediate goal while developing software. Therefore, this is OK for now.
|
||||
|
||||
However, once the software is ready for release, it doesn't need to have the debugging information anymore. But it does need to be optimized for best performance. In the final stages of development, you can use the **\--release** flag with **build**. Watch closely; you should see the **[optimized]** text after compilation:
|
||||
|
||||
|
||||
```
|
||||
$ cargo build --release
|
||||
Compiling hello_opensource v0.1.0 (/opensource/hello_opensource)
|
||||
Finished release [optimized] target(s) in 0.29s
|
||||
```
|
||||
|
||||
If you want to, you can go through the exercise to find out your time savings when running optimized vs. unoptimized software.
|
||||
|
||||
### Creating a library vs. a binary using Cargo
|
||||
|
||||
Any software program can be roughly categorized as either a standalone binary or a library. A standalone binary can be run as it is, even though it might make use of external libraries. A library, however, is utilized by another standalone binary. All the programs you've built so far in this tutorial are standalone binaries since that is Cargo's default. To create a **library**, add the **\--lib** option:
|
||||
|
||||
|
||||
```
|
||||
$ cargo new --lib libhello
|
||||
Created library `libhello` package
|
||||
```
|
||||
|
||||
This time, Cargo does not create a **main.rs** file; instead, it creates a **lib.rs** file. The code for your library should go here:
|
||||
|
||||
|
||||
```
|
||||
$ tree .
|
||||
.
|
||||
└── libhello
|
||||
├── Cargo.toml
|
||||
└── src
|
||||
└── lib.rs
|
||||
|
||||
2 directories, 2 files
|
||||
```
|
||||
|
||||
Knowing Cargo, don't be surprised that it put some code in your new library file. Find out what it added by moving to the package directory and viewing the file. By default, Cargo puts a test function within library files.
|
||||
|
||||
### Running tests using Cargo
|
||||
|
||||
Rust provides first-class support for unit and integration testing, and Cargo allows you to execute any of these tests:
|
||||
|
||||
|
||||
```
|
||||
$ cd libhello/
|
||||
|
||||
$ cat src/lib.rs
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(2 + 2, 4);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Cargo has a handy **test** option to run any test that is present in your code. Try running the tests that Cargo put in the library code by default:
|
||||
|
||||
|
||||
```
|
||||
$ cargo test
|
||||
Compiling libhello v0.1.0 (/opensource/libhello)
|
||||
Finished test [unoptimized + debuginfo] target(s) in 0.55s
|
||||
Running target/debug/deps/libhello-d52e35bb47939653
|
||||
|
||||
running 1 test
|
||||
test tests::it_works ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
|
||||
|
||||
Doc-tests libhello
|
||||
|
||||
running 0 tests
|
||||
|
||||
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
|
||||
```
|
||||
|
||||
### Looking under Cargo's hood
|
||||
|
||||
You may be interested in knowing what Cargo does under the hood when you run a command. After all, Cargo is, in many ways, a wrapper. To find out what it's doing, you can use the **-v** option with any Cargo command to output verbose information to the screen.
|
||||
|
||||
Here are a couple of examples that run **build** and **clean** using the **-v** option.
|
||||
|
||||
In the **build** command, you can see that the underlying **rustc** (Rust compiler) fired with the given command-line options:
|
||||
|
||||
|
||||
```
|
||||
$ cargo build -v
|
||||
Compiling hello_opensource v0.1.0 (/opensource/hello_opensource)
|
||||
Running `rustc --edition=2018 --crate-name hello_opensource src/main.rs --error-format=json --json=diagnostic-rendered-ansi --crate-type bin --emit=dep-info,link -C debuginfo=2 -C metadata=147b8a0f466515dd -C extra-filename=-147b8a0f466515dd --out-dir /opensource/hello_opensource/target/debug/deps -C incremental=/opensource/hello_opensource/target/debug/incremental -L dependency=/opensource/hello_opensource/target/debug/deps`
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 0.36s
|
||||
```
|
||||
|
||||
Whereas the **clean** command shows that it is simply removing the directory that contains the intermediate files and the binary:
|
||||
|
||||
|
||||
```
|
||||
$ cargo clean -v
|
||||
Removing /opensource/hello_opensource/target
|
||||
```
|
||||
|
||||
### Don't let your skills get rusty
|
||||
|
||||
To expand your skills, try writing and running a slightly more complex program using Rust and Cargo. Something simple will do: for instance, try listing all files in the current directory (it can be done in nine lines of code), or try echoing input back out at yourself. Small practice applications help you get comfortable with the syntax and the process of writing and testing code.
|
||||
|
||||
This article offers plenty of information for budding Rust programmers to get started with Cargo. However, as you begin working on larger and more complicated programs, you'll need a more advanced understanding of Cargo. When you're ready for more, download and read the open source [Cargo Book][10] written by the Rust team, and see what you can create!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/3/rust-cargo
|
||||
|
||||
作者:[Gaurav Kamathe][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/gkamathe
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/bus-containers2.png?itok=idd8duC_ (Shipping containers stacked in a yard)
|
||||
[2]: https://www.rust-lang.org/
|
||||
[3]: https://insights.stackoverflow.com/survey/2019#technology-_-most-loved-dreaded-and-wanted-languages
|
||||
[4]: https://sh.rustup.rs/
|
||||
[5]: https://www.rust-lang.org/tools/install
|
||||
[6]: https://doc.rust-lang.org/cargo/faq.html
|
||||
[7]: mailto:user@mail.com
|
||||
[8]: mailto:test@mail.com
|
||||
[9]: http://crates.io
|
||||
[10]: https://doc.rust-lang.org/cargo
|
||||
@@ -1,5 +1,5 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (HankChow)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Getting started with the Gutenberg editor in Drupal)
|
||||
[#]: via: (https://opensource.com/article/20/3/gutenberg-editor-drupal)
|
||||
[#]: author: (MaciejLukianski https://opensource.com/users/maciejlukianski)
|
||||
|
||||
Getting started with the Gutenberg editor in Drupal
|
||||
======
|
||||
Learn how to use the WYSIWYG editor, made popular in WordPress, with
|
||||
Drupal.
|
||||
![Text editor on a browser, in blue][1]
|
||||
|
||||
Since 2017, WordPress has had a really great WYSIWYG editor in the [Gutenberg][2] plugin. But the Drupal community hasn't yet reached consensus on the best approach to the content management system's (CMS) editorial experience. But a strong new option appeared when, with a lot of community effort, [Gutenberg was integrated with Drupal][3].
|
||||
|
||||
Previously, there were two main approaches to content creation in Drupal 8:
|
||||
|
||||
* In the [**Paragraph-based approach**][4], content is assembled out of entities called paragraphs. Currently, approximately 100,000 websites use the Paragraphs module (according to Drupal).
|
||||
* The [**Layout-Builder approach**][5] uses an editorial tool shipped with Drupal 8.5. It is still undergoing improvements, but it is the next strong contender because it is really well integrated with the Drupal core. Stats on usage are not available since Layout Builder is part of Drupal.
|
||||
|
||||
|
||||
|
||||
At the end of 2018, the Drupal community, lead by Fronkom (a Norwegian digital agency strongly focused on open source solutions), ported the WordPress Gutenberg project as a contributed module into Drupal. Let's take a look at how Gutenberg works in Drupal (including some cool Drupal-specific integrations).
|
||||
|
||||
### Installation
|
||||
|
||||
Installing the [Gutenberg module][6] is as straightforward as installing any Drupal module, and it has good [installation documentation][7].
|
||||
|
||||
### Configuration
|
||||
|
||||
Gutenberg is integrated into Drupal's default content-entity creation workflow. You can use it on any of the content types you choose, provided that the content type has at least one text area field, which is where the Gutenberg editor's output will be saved.
|
||||
|
||||
To enable the Gutenberg project on a content type in Drupal, you have to navigate to its settings: **Structure > Content types** and, from the dropdown next to the content type where you want to use Gutenberg, click **Edit**.
|
||||
|
||||
![Drupal settings][8]
|
||||
|
||||
In the form that appears, scroll down and select the **Gutenberg experience** tab on the left, where you can find the settings described below. Select the **Enable Gutenberg experience** box.
|
||||
|
||||
![Drupal Gutenberg settings][9]
|
||||
|
||||
#### Template
|
||||
|
||||
This is one of the cool features that is not available in WordPress out of the box. It enables you to define a template for a new page in a JSON structure. This will pre-populate all newly created articles with dummy placeholder content, which will help editors structure content correctly. In the screenshot above, I added a heading and a paragraph. Note that any double-quotes have to be escaped.
|
||||
|
||||
#### Template lock
|
||||
|
||||
This setting allows you to define whether users are allowed to delete the placeholder content, add new blocks, or just edit the existing, pre-populated content.
|
||||
|
||||
#### Allowed Gutenberg and Drupal blocks
|
||||
|
||||
This is another super-cool feature on the Drupal side of Gutenberg. Drupal allows users to create various types of blocks to design a page. For example, you could create a block with a list of the five latest blog posts, the most recent comments, or a form to collect users' emails.
|
||||
|
||||
Gutenberg's deep integration with Drupal allows users to select which Drupal blocks are available to users while they are editing (e.g., limit embeds to YouTube) and use blocks as inline content. This is a very handy feature that allows granular control of the user experience.
|
||||
|
||||
There's not much to choose from in a blank Drupal installation, but a live site usually has many blocks that provide various functionalities. In the screenshot below, the **Search form** Drupal block is selected.
|
||||
|
||||
![Drupal Gutenberg blocks][10]
|
||||
|
||||
After you finish the configuration, hit **Save content type**.
|
||||
|
||||
### Publishing content with Drupal Gutenberg
|
||||
|
||||
When Gutenberg is enabled for a content type, it takes over most of the editorial experience.
|
||||
|
||||
![Drupal Gutenberg content screen][11]
|
||||
|
||||
In the main window, you can see the dummy placeholder content I added in the Template configuration above.
|
||||
|
||||
#### Drupal-specific options
|
||||
|
||||
On the right-hand side, there are a few fields and settings that Drupal provides. For example, the **Title** field is a required separate field in Drupal, and therefore it is not on the main Gutenberg screen.
|
||||
|
||||
Underneath the **Title**, there are additional settings that can vary, depending on the modules installed and options set up in Drupal. You can see **Revision log messages**, **Menu settings**, **Comment settings**, and a place to add a **URL alias**.
|
||||
|
||||
Typically, Drupal content types are composed of several text fields, such as tags, categories, checkboxes, image fields for teasers, etc. When you enable Gutenberg for a content type, these additional fields are available in the **More settings** tab.
|
||||
|
||||
You can now add your content—it works the same as it does in WordPress Gutenberg, with the additional option to add Drupal blocks.
|
||||
|
||||
In the screenshot below, you can see what happens when I add some text to replace the placeholder text, a search block from Drupal, a title, tags, and a custom URL alias.
|
||||
|
||||
![Drupal Gutenberg entering text][12]
|
||||
|
||||
After you hit **Save**, your content will be published.
|
||||
|
||||
![Drupal Gutenberg output][13]
|
||||
|
||||
And that is it. It works like a charm!
|
||||
|
||||
### Working together for better software experiences
|
||||
|
||||
Gutenberg in Drupal works well. It is an alternative option that allows editors to control the look and feel of their websites down to the tiniest details. Adoption is growing well, with over 1,000 installations as of this writing and 50 new ones every month. The Drupal integration adds other cool features like fine-grained permissions, placeholder content, and the ability to include Drupal blocks inline, which aren't available in the WordPress plugin.
|
||||
|
||||
It is great to see the communities of two separate projects working together to achieve the common goal of giving people better software.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/3/gutenberg-editor-drupal
|
||||
|
||||
作者:[MaciejLukianski][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/maciejlukianski
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/browser_blue_text_editor_web.png?itok=lcf-m6N7 (Text editor on a browser, in blue)
|
||||
[2]: https://wordpress.org/plugins/gutenberg/
|
||||
[3]: https://drupalgutenberg.org/
|
||||
[4]: https://www.droptica.com/blog/flexible-and-easy-content-creation-drupal-paragraphs-module/
|
||||
[5]: https://www.droptica.com/blog/layout-builder-building-drupal-8-layouts/
|
||||
[6]: https://www.drupal.org/project/gutenberg
|
||||
[7]: https://www.drupal.org/docs/8/extending-drupal-8/installing-drupal-8-modules
|
||||
[8]: https://opensource.com/sites/default/files/uploads/gutenberg_edit.png (Drupal settings)
|
||||
[9]: https://opensource.com/sites/default/files/uploads/gutenberg_settings.png (Drupal Gutenberg settings)
|
||||
[10]: https://opensource.com/sites/default/files/uploads/gutenberg_blocks.png (Drupal Gutenberg blocks)
|
||||
[11]: https://opensource.com/sites/default/files/uploads/gutenberg_contentwindow.png (Drupal Gutenberg content screen)
|
||||
[12]: https://opensource.com/sites/default/files/uploads/gutenberg_entry.png (Drupal Gutenberg entering text)
|
||||
[13]: https://opensource.com/sites/default/files/uploads/gutenberg-demo.png (Drupal Gutenberg output)
|
||||
@@ -0,0 +1,428 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How service virtualization relates to test-driven development)
|
||||
[#]: via: (https://opensource.com/article/20/3/service-virtualization-test-driven-development)
|
||||
[#]: author: (Alex Bunardzic https://opensource.com/users/alex-bunardzic)
|
||||
|
||||
How service virtualization relates to test-driven development
|
||||
======
|
||||
Mountebank simulates services you're dependent on so autonomous teams
|
||||
can continue development activities without having to wait on anyone.
|
||||
![Person using a laptop][1]
|
||||
|
||||
The agile approach to software development relies on service virtualization to give each IT team autonomy. This approach removes blockages and allows autonomous teams to continue development activities without having to wait on anyone. That way, integration testing can commence as soon as teams start iterating/sprinting.
|
||||
|
||||
### How automated services work
|
||||
|
||||
Any automated service is available to consumers via a published endpoint. This means services can be automated only if they're made available online.
|
||||
|
||||
Any consumer wishing to leverage available automated services must be capable of sending requests to that service's endpoint via an HTTP protocol. Some of those services will, upon receiving the request via the HTTP protocol, respond by simply sending back some data. Other services may respond to receiving a request via HTTP protocol by actually performing some work. For example, a service may create a resource (for example, create an order), update a resource (update an order), or delete a resource (cancel an order).
|
||||
|
||||
All those activities get triggered via the HTTP protocol. In the simplest of cases, the action instigated by the service consumer is GET (e.g., HTTP GET). That request may arrive with some query values; those values will get used by the service to narrow down the search (such as "search for order number 12345 and return the data").
|
||||
|
||||
In more elaborate cases, a request may arrive with the instruction to POST some values; a service will accept that request and expect some values to be associated with it. Those values are usually called the payload. When the service accepts an HTTP POST request containing the payload, it will attempt to process it. It may or may not succeed in processing it, but either way, it will respond to the service consumer with a status code and an optional status message. That way, service consumers will be notified of the success/failure of their request so that they can decide what the next step should be.
|
||||
|
||||
### What is service virtualization?
|
||||
|
||||
Now that we understand how automated services work, it should be easier to understand how to virtualize them. In a nutshell, it is possible to simulate any service that is published on a hosting site. Instead of sending HTTP requests directly to the service provider's endpoint, you can interject a fake, pretend service that simulates the behavior of the real service.
|
||||
|
||||
From the service consumer's standpoint, it makes absolutely no difference whether it is interacting with a real or a fake service. The interaction remains identical.
|
||||
|
||||
### Virtualize one service
|
||||
|
||||
OK, enough talking, I'll roll up my sleeves and show how to do it in practical terms. Suppose your team is starting a new project and receives requirements in the form of a fully fleshed user story:
|
||||
|
||||
#### Authenticate user
|
||||
|
||||
_As a new app_
|
||||
_I want to authenticate the user_
|
||||
_Because we want to ensure proper security for the app_
|
||||
|
||||
#### Acceptance criteria
|
||||
|
||||
**Scenario #1:** _New app successfully authenticates the user_
|
||||
Given that the user has navigated to the login page
|
||||
And the user has submitted credentials
|
||||
When new app receives login request
|
||||
Then new app successfully authenticates the user
|
||||
And new app displays response message "User successfully logged in."
|
||||
|
||||
**Scenario #2:** _New app cannot authenticate the user on the first attempt_
|
||||
Given that the user has navigated to the login page
|
||||
And the user has submitted credentials
|
||||
When new app receives login request
|
||||
Then new app fails to successfully authenticate the user
|
||||
And new app displays response message "Incorrect login. You have 2 more attempts left."
|
||||
|
||||
**Scenario #3:** _New app cannot authenticate the user on the second attempt_
|
||||
Given that the user has navigated to the login page
|
||||
And the user has submitted credentials
|
||||
When new app receives login request
|
||||
Then new app fails to successfully authenticate the user
|
||||
And new app displays response message "Incorrect login. You have 1 more attempt left."
|
||||
|
||||
**Scenario #4:** _New app cannot authenticate the user on the third attempt_
|
||||
Given that the user has navigated to the login page
|
||||
And the user has submitted credentials
|
||||
When new app receives login request
|
||||
Then new app fails to successfully authenticate the user
|
||||
And new app displays response message "Incorrect login. You have no more attempts left."
|
||||
|
||||
The first thing to do when starting the work on this user story is to create the so-called "walking skeleton" (for this exercise, I will be using the standard **.Net Core** platform plus **xUnit.net** I discussed in my previous articles ([starting with this one][2] with [another example here][3]). Please refer to them for technical details on how to install, configure, and run the required tools.
|
||||
|
||||
Create the walking skeleton infrastructure by opening the command line and typing:
|
||||
|
||||
|
||||
```
|
||||
`mkdir AuthenticateUser`
|
||||
```
|
||||
|
||||
Then move inside the **AuthenticateUser** folder:
|
||||
|
||||
|
||||
```
|
||||
`cd AuthenticateUser`
|
||||
```
|
||||
|
||||
And create a separate folder for tests:
|
||||
|
||||
|
||||
```
|
||||
`mkdir tests`
|
||||
```
|
||||
|
||||
Move into the **tests** folder (**cd tests**) and initiate the **xUnit** framework:
|
||||
|
||||
|
||||
```
|
||||
`dotnet new xunit`
|
||||
```
|
||||
|
||||
Now move one folder up (back to **AuthenticateUser**) and create the app folder:
|
||||
|
||||
|
||||
```
|
||||
mkdir app
|
||||
cd app
|
||||
```
|
||||
|
||||
Create the scaffold necessary for C# code:
|
||||
|
||||
|
||||
```
|
||||
`dotnet new classlib`
|
||||
```
|
||||
|
||||
The walking skeleton is now ready! Open the editor of your choice and start coding.
|
||||
|
||||
### Write a failing test first
|
||||
|
||||
In the spirit of TDD, start by writing the failing test (refer to the [previous article][4] to learn why is it important to see your test fail before attempting to make it pass):
|
||||
|
||||
|
||||
```
|
||||
using System;
|
||||
using Xunit;
|
||||
using app;
|
||||
|
||||
namespace tests {
|
||||
public class UnitTest1 {
|
||||
Authenticate auth = [new][5] Authenticate();
|
||||
|
||||
[Fact]
|
||||
public void SuccessLogin(){
|
||||
var given = "credentials";
|
||||
var expected = "Successful login.";
|
||||
var actual = auth.Login(given);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This test states that if someone supplies some credentials (i.e., a secret username and password) to the **Login** method of the **Authenticate** component when it processes the request, it is expected to return the message "Successful login."
|
||||
|
||||
Of course, this is functionality that does not exist yet—the instantiated **Authenticate** module in the **SuccessLogin()** module hasn't been written yet. So you might as well go ahead and take the first stab at writing the desired functionality. Create a new file (**Authenticate.cs**) in the **app** folder and add the following code:
|
||||
|
||||
|
||||
```
|
||||
using System;
|
||||
|
||||
namespace app {
|
||||
public class Authenticate {
|
||||
public string Login(string credentials) {
|
||||
return "Not implemented";
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now, navigate to the **tests** folder and run:
|
||||
|
||||
|
||||
```
|
||||
`dotnet test`
|
||||
```
|
||||
|
||||
![Output of dotnet.test][6]
|
||||
|
||||
The test fails because it was expecting a "Successful login" output but instead got the "Not implemented" output.
|
||||
|
||||
### Increasing complexity for day two operations
|
||||
|
||||
Now that you have created the "happy path" expectation and made it fail, it is time to work on implementing the functionality that will make the failing test pass. The following day, you attend the standup and report that you have started on the "Authenticate user" story. You let the team know that you have created the first failing test for the "happy path," and today, the plan is to implement the code to make the failing test pass.
|
||||
|
||||
You explain your intention to first create a **User** table containing the **username**, **password**, and other pertinent attributes. But the scrum master interrupts and explains that the **User** module is being handled by another team. It would be bad practice to duplicate the maintenance of users, as the information will quickly get out of sync. So instead of building the **User** module (which would include the authentication logic), you are to leverage the authentication services that the **User** team is working on.
|
||||
|
||||
That's great news because it saves you the trouble of having to write a lot of code to implement the **User** processing. Emboldened, you enthusiastically announce that you will quickly cobble up a function that will take user credentials and send them to the service that the **User** team has built.
|
||||
|
||||
Alas, your intentions get squashed again as you learn that the **User** team hasn't started building the **User authentication** service yet. They're still in the process of assigning user stories to the backlog. Disheartened, you resign to the fact that it will be at least a few days (if not weeks?) before you can start working on the **User authentication** story.
|
||||
|
||||
The scrum master then says that there is no reason to wait for the **User authentication** service to be built and deployed to testing. You could start developing the authentication functionality right away. But how can you do that?
|
||||
|
||||
The scrum master offers a simple suggestion: leverage service virtualization. Since all specifications for the **User** module have been solidified and signed off, you have a solid, non-volatile contract to build your solution against. The contract published by the **User** services team states that in order to authenticate a user, specific expectations must be fulfilled:
|
||||
|
||||
1. A client wishing to authenticate a user should send an **HTTP POST** request to the endpoint <http://some-domain.com/api/v1/users/login>.
|
||||
2. The **HTTP POST** sent to the above endpoint must have a **JSON** payload that contains the user credentials (i.e., username and password).
|
||||
3. Upon receiving the request, the service will attempt to log the user in. If the username and password match the information on record, the service will return an **HTTP** response containing status code 200 with the body of the response containing the message "User successfully logged in."
|
||||
|
||||
|
||||
|
||||
So, now that you know the contract details, you can start building the solution. Here's the code that connects to the endpoint, sends the **HTTP POST** request, and receives the **HTTP** response:
|
||||
|
||||
|
||||
```
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace app {
|
||||
public class Authenticate {
|
||||
HttpClient client = [new][5] HttpClient();
|
||||
string endPoint = "<http://some-domain.com/api/v1/users/login>";
|
||||
|
||||
public string Login(string credentials) {
|
||||
Task<string> response = CheckLogin(credentials);
|
||||
return response.Result;
|
||||
}
|
||||
|
||||
private async Task<string> CheckLogin(string credentials) {
|
||||
var values = [new][5] Dictionary<string, string>{{"credentials", credentials}};
|
||||
var content = [new][5] FormUrlEncodedContent(values);
|
||||
var response = await client.PostAsync(endPoint, content);
|
||||
return await response.Content.ReadAsStringAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This code won't work because <http://some-domain.com> does not exist (yet). Are you stuck now, waiting for the other team to eventually build and deploy that service?
|
||||
|
||||
Not really. Service virtualization to rescue! Let's pretend that the service is already there and continue the development.
|
||||
|
||||
### How to virtualize a service
|
||||
|
||||
One way to virtualize the **User authentication** service would be to write a new app (the new API) and run it locally. This API will mirror the contract specified by the real **User authentication** API and will only return hard-coded stubbed data (it will be a fake service).
|
||||
|
||||
Sounds like a good plan. Again, the team pushes back during the standup, questioning the need for writing, building, testing, and deploying a brand new app just to accomplish this fake functionality. It kind of wouldn't be worth the trouble because, by the time you deliver that new fake app, the other team would probably be ready with the real service.
|
||||
|
||||
So you've reached an impasse. It looks like you are forced to wait on your dependency to materialize. You've failed to control your dependencies; you now have no recourse but to work in a sequential fashion.
|
||||
|
||||
Not so fast! There is a great new tool called [mountebank][7] that is ideal for virtualizing any service. Using this tool, you can quickly stand up a local server that listens on a port you specify and takes orders. To make it simulate a service, you only have to tell it which port to listen to and which protocol to handle. The choice of protocols is:
|
||||
|
||||
* HTTP
|
||||
* HTTPS
|
||||
* SMTP
|
||||
* TCP
|
||||
|
||||
|
||||
|
||||
In this case, you need the HTTP protocol. First, install mountebank—if you have **npm** on your computer, you can simply type on the command line:
|
||||
|
||||
|
||||
```
|
||||
`npm install -g mountebank`
|
||||
```
|
||||
|
||||
After it's installed, run mountebank by typing:
|
||||
|
||||
|
||||
```
|
||||
`mb`
|
||||
```
|
||||
|
||||
At startup, mountebank will show:
|
||||
|
||||
![mountebank startup][8]
|
||||
|
||||
Now you're ready to virtualize an HTTP service. In this case, the **User authentication** service expects to receive an HTTP POST request; here is how the implemented code sends an HTTP POST request:
|
||||
|
||||
|
||||
```
|
||||
`var response = await client.PostAsync(endPoint, content);`
|
||||
```
|
||||
|
||||
You now have to establish that **endPoint**. Ideally, all virtualized services should be propped in the **localhost** server to ensure quick execution of integration tests.
|
||||
|
||||
To do that, you need to configure the **imposter**. In its bare-bones form, the **imposter** is a simple JSON collection of key-value pairs containing the definition of a port and a protocol:
|
||||
|
||||
|
||||
```
|
||||
{
|
||||
"port": 3001,
|
||||
"protocol": "http"
|
||||
}
|
||||
```
|
||||
|
||||
This imposter is configured to handle the HTTP protocol and to listen to incoming requests on port 3001.
|
||||
|
||||
Just listening to incoming HTTP requests on port 3001 is not going to do much. Once the request arrives at that port, mountebank needs to be told what to do with that request. In other words, you are virtualizing not only the availability of a service on a specific port but also the way that virtualized service is going to respond to the request.
|
||||
|
||||
To accomplish that level of service virtualization, you need to tell mountebank how to configure stubs. Each stub consists of two components:
|
||||
|
||||
1. A collection of predicates
|
||||
2. A collection of expected responses
|
||||
|
||||
|
||||
|
||||
A predicate (sometimes called a matcher) narrows down the scope of the incoming request. For example, using the HTTP protocol, you can expect more than one type of method (e.g., GET, POST, PUT, DELETE, PATCH, etc.). In most service-virtualization scenarios, we are interested in simulating the behavior that is specific to a particular HTTP method. This scenario is about responding to the HTTP POST request, so you need to configure your stub to match on HTTP POST requests only:
|
||||
|
||||
|
||||
```
|
||||
{
|
||||
"port": 3001,
|
||||
"protocol": "http",
|
||||
"stubs": [
|
||||
{
|
||||
"predicates": [
|
||||
{
|
||||
"equals": {
|
||||
"method": "post"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
This imposter defines one predicate that matches (using the keyword **equals**) on the HTTP POST request only.
|
||||
|
||||
Now take a closer look at the **endPoint** value, as defined in the implemented code:
|
||||
|
||||
|
||||
```
|
||||
`string endPoint = "http://localhost:3001/api/v1/users/login";`
|
||||
```
|
||||
|
||||
In addition to listening to port 3001 (as defined in <http://localhost:3001>), the **endPoint** is more specific, in that it expects the incoming HTTP POST request to go to the /api/v1/users/login path. How do you tell mountebank to only match exactly on the /api/v1/users/login path? By adding the path key-value pair to the stub's predicate:
|
||||
|
||||
|
||||
```
|
||||
{
|
||||
"port": 3001,
|
||||
"protocol": "http",
|
||||
"stubs": [
|
||||
{
|
||||
"predicates": [
|
||||
{
|
||||
"equals": {
|
||||
"method": "post",
|
||||
"path": "/api/v1/users/login"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
This imposter now knows that HTTP requests arriving at port 3001 must be a POST method and must point at the /api/v1/users/login path. The only thing left to simulate is the expected HTTP response.
|
||||
|
||||
Add the response to the JSON imposter:
|
||||
|
||||
|
||||
```
|
||||
{
|
||||
"port": 3001,
|
||||
"protocol": "http",
|
||||
"stubs": [
|
||||
{
|
||||
"predicates": [
|
||||
{
|
||||
"equals": {
|
||||
"method": "post",
|
||||
"path": "/api/v1/users/login"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": [
|
||||
{
|
||||
"is": {
|
||||
"statusCode": 200,
|
||||
"body": "Successful login."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
With mountebank imposters, you define responses as a collection of JSON key-value pairs. In most cases, it is sufficient to simply state that a response is a **statusCode** and a **body**. This case is simulating the "happy path" response that has the status code **OK (200)** and the body containing a simple message **Successful login** (as specified in the acceptance criteria).
|
||||
|
||||
### How to run virtualized services?
|
||||
|
||||
OK, now that you have virtualized the **User authentication** service (at least its "happy path"), how do you run it?
|
||||
|
||||
Remember that you have already started mountebank, and it reported that it is running in memory as the <http://localhost> domain. Mountebank is listening on port 2525 and taking orders.
|
||||
|
||||
Great, now you have to tell mountebank that you have the imposter ready. How do you do that? Send an HTTP POST request to <http://localhost:2525/imposters>. The requests body must contain the JSON you created above. There are a few techniques available to send that request. If you're versed in [curl][9], using it to send HTTP POST requests would be the simplest, quickest way to stand up the imposter. But many people prefer a more user-friendly way to send the HTTP POST to mountebank.
|
||||
|
||||
The easy way to do that is to use [Postman][10]. If you download and install Postman, you can point it at <http://localhost:2525/imposters>, select the POST method from the pulldown menu, and copy and paste the imposter JSON into the raw body.
|
||||
|
||||
When you click Send, the imposter will be created, and you should get Status 201 (Created).
|
||||
|
||||
![Postman output][11]
|
||||
|
||||
Your virtualized service is now running! You can verify it by navigating to the **tests** folder and running the **dotnet test** command:
|
||||
|
||||
![dotnet test output][12]
|
||||
|
||||
### Conclusion
|
||||
|
||||
This demo shows how easy it is to remove blockages and control dependencies by simulating services you're dependent on. Mountebank is a fantastic tool that easily and cheaply simulates all kinds of very elaborate, sophisticated services.
|
||||
|
||||
In this installment, I just had time to illustrate how to virtualize a simple "happy path" service. If you go back to the actual user story, you will notice that its acceptance criteria contain several "less happy" paths (cases when someone is repeatedly trying to log in using invalid credentials). It's a bit trickier to properly virtualize and test those use cases, so I've left that exercise for the next installment in this series.
|
||||
|
||||
How will you use service virtualization to solve your testing needs? I would love to hear about it in the comments.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/3/service-virtualization-test-driven-development
|
||||
|
||||
作者:[Alex Bunardzic][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/alex-bunardzic
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/laptop_screen_desk_work_chat_text.png?itok=UXqIDRDD (Person using a laptop)
|
||||
[2]: https://opensource.com/article/19/8/mutation-testing-evolution-tdd
|
||||
[3]: https://opensource.com/article/19/9/mutation-testing-example-tdd
|
||||
[4]: https://opensource.com/article/20/2/automate-unit-tests
|
||||
[5]: http://www.google.com/search?q=new+msdn.microsoft.com
|
||||
[6]: https://opensource.com/sites/default/files/uploads/dotnet-test.png (Output of dotnet.test)
|
||||
[7]: http://www.mbtest.org/
|
||||
[8]: https://opensource.com/sites/default/files/uploads/mountebank-startup.png (mountebank startup)
|
||||
[9]: https://curl.haxx.se/
|
||||
[10]: https://www.postman.com/
|
||||
[11]: https://opensource.com/sites/default/files/uploads/status-201.png (Postman output)
|
||||
[12]: https://opensource.com/sites/default/files/uploads/dotnet-test2.png (dotnet test output)
|
||||
153
sources/tech/20200305 5 productivity apps for Linux.md
Normal file
153
sources/tech/20200305 5 productivity apps for Linux.md
Normal file
@@ -0,0 +1,153 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (5 productivity apps for Linux)
|
||||
[#]: via: (https://opensource.com/article/20/3/productivity-apps-linux-elementary)
|
||||
[#]: author: (Scott Nesbitt https://opensource.com/users/scottnesbitt)
|
||||
|
||||
5 productivity apps for Linux
|
||||
======
|
||||
Get organized and accomplish more with these five productivity apps for
|
||||
the Elementary Linux desktop.
|
||||
![Person drinking a hat drink at the computer][1]
|
||||
|
||||
I've had a soft spot for [Elementary OS][2] since I first encountered it in 2013. A lot of that has to do with the distribution being very clean and simple.
|
||||
|
||||
Since 2013, I've recommended Elementary to people who I've helped [transition to Linux][3] from other operating systems. Some have stuck with it. Some who moved on to other Linux distributions told me that Elementary helped smooth the transition and gave them more confidence using Linux.
|
||||
|
||||
Like the distribution itself, many of the applications created specifically for Elementary OS are simple, clean, and useful. They can help boost your day-to-day productivity, too.
|
||||
|
||||
### About "pay-what-you-want" apps
|
||||
|
||||
Some apps in the Elementary AppCenter ask you to pay what you can. You're not obliged to pay to the full amount a developer asks for (or pay anything, for that matter). However, any money that changes hands goes to support the development of those apps.
|
||||
|
||||
Three of the applications in this article—Quilter, Notes-up, and Envelope—are pay-what-you-want. If you find an app useful, I encourage you to send some money the developer's way.
|
||||
|
||||
### Envelope
|
||||
|
||||
Managing your budget should be simple. More than a few people, though, struggle with the task. That's where [Envelope][4] can help. While Envelope doesn't pack the features of something like [GnuCash][5], it's good enough for most of us.
|
||||
|
||||
The app is built around the [envelope system][6] of personal and household budgeting. The first time you launch Envelope, you need to set up an account. You can do that manually, or you can import a [QIF][7] file containing financial information from another program.
|
||||
|
||||
![Adding an account in Envelope][8]
|
||||
|
||||
Either way, Envelope offers a set of categories (your envelopes). Add or delete categories as you see fit—for example, I don't own a car, so I deleted the Fuel category.
|
||||
|
||||
From there, add transactions. Those can be your expenses or your income. Or both.
|
||||
|
||||
![Entering a transaction in Envelope][9]
|
||||
|
||||
Envelope gives you an overview of your spending and income. To get a more focused view of your budget, you can report on the current or previous month or a specific range of dates.
|
||||
|
||||
### Notes-Up
|
||||
|
||||
[Notes-Up][10]'s look and feel are reminiscent of note-taking tools like [Standard Notes][11], Simplenote, and the macOS Notes app. If you use any of them, switching to Notes-Up will be smooth and painless. Regardless, Notes-Up is easy to learn and use.
|
||||
|
||||
![Notes-Up][12]
|
||||
|
||||
Create a note and start typing. Notes-Up supports Markdown, making it easy to add formatting to your notes.
|
||||
|
||||
![Taking notes in Notes-Up][13]
|
||||
|
||||
If your Markdown is rusty, you can click the buttons on the toolbar to add formatting like lists; bold, italics, and strikethrough; code blocks; images; and more. You can also export your notes as PDF or Markdown files.
|
||||
|
||||
Use Notes-Up for a while, and you'll wind up with a long list of notes. Organize them using _notebooks_. You can, for example, create personal, school, and work notebooks. On top of that, Notes-Up enables you to create sub-notebooks. Under my notebook for Opensource.com, for example, I have sub-notebooks for articles and the news roundups I curate.
|
||||
|
||||
Notebooks not your thing? Then use tags to add keywords to your notes to make them easier to sort.
|
||||
|
||||
### Yishu
|
||||
|
||||
I do as much of my work as I can in [plain text][14]. That includes my task list. For that, I turn to a handy command-line application called [Todo.txt][15].
|
||||
|
||||
If you aren't comfortable working at the command line, then [Yishu][16] is for you. It has Todo.txt's key features but graphically on the desktop.
|
||||
|
||||
![Yishu][17]
|
||||
|
||||
When you first fire up Yishu, it asks you to open an existing Todo.txt file. If you have one, open it. Otherwise, create a task. That also creates a new file for your tasks.
|
||||
|
||||
![Adding a task in Yishu][18]
|
||||
|
||||
Your options are limited: a description of the task and a priority. You can also add a due date in the format _YYYY-MM-DD_—for example, _2020-02-17_.
|
||||
|
||||
When you click **OK**, Yishu saves the file Todo.txt to your **/home** folder. That might not be where you want to store your tasks. You can tell Yishu to use another folder in its preferences.
|
||||
|
||||
### Reminduck
|
||||
|
||||
Chances are, your notifications and reminders are jarring. A piercing buzz, an annoying beep, a text box that appears when you least expect it. Why not add a bit of [calm][19] and a bit of whimsy to your reminders—with a duck?
|
||||
|
||||
That's the idea behind [Reminduck][20]. It's a simple and fun way to tell yourself it's time to do, well, anything.
|
||||
|
||||
Fire up the app and create a reminder. You can add a description, date, and time for the reminder to appear, and you can set it to repeat. Reminders can repeat after a number of minutes that you set or at specific times every day, week, or month.
|
||||
|
||||
![Reminduck][21]
|
||||
|
||||
You can set up more than one reminder. Reminduck organizes your reminders, and you can edit or delete them.
|
||||
|
||||
![Reminduck reminders][22]
|
||||
|
||||
When the reminder is triggered, a little message pops out of the notification area on the desktop along with a soft alert and an icon of a smiling duck.
|
||||
|
||||
![Reminduck notification][23]
|
||||
|
||||
### Quilter
|
||||
|
||||
It's easy enough to write with [Markdown][24] in a plain old text editor. Some folks, though, prefer to work with a dedicated Markdown editor. On the Elementary OS desktop, one option is [Quilter][25].
|
||||
|
||||
![Quilter][26]
|
||||
|
||||
Quilter is pretty basic. There's no toolbar to insert formatting; you have to add Markdown by hand. On the other hand, Quilter displays a running word count and an estimate of how long it will take to read what you're writing.
|
||||
|
||||
![Quilter][27]
|
||||
|
||||
The editor's options are few. There's a preview mode, and you can export your documents to PDF or HTML. The result of an export has the same look as a preview. That's not a bad thing.
|
||||
|
||||
Quilter's other options include the ability to change the line spacing and margins, set the editor's font, as well as enable syntax highlighting and spell checking. It also has a mode that you can use to focus on a single line or a single paragraph while you're writing.
|
||||
|
||||
### Final thoughts
|
||||
|
||||
Sometimes, the best tools to boost your productivity are simple ones. Applications like the five above focus on doing one thing and doing it well.
|
||||
|
||||
Envelope, Notes-Up, Yishu, Reminduck, and Quilter won't appeal to everyone. But if you use Elementary OS, give them a try. They can help you keep on track and do what you need to do.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/3/productivity-apps-linux-elementary
|
||||
|
||||
作者:[Scott Nesbitt][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/scottnesbitt
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/coffee_tea_laptop_computer_work_desk.png?itok=D5yMx_Dr (Person drinking a hat drink at the computer)
|
||||
[2]: https://elementary.io
|
||||
[3]: https://opensource.com/article/18/12/help-non-techies
|
||||
[4]: https://nlaplante.github.io/envelope/
|
||||
[5]: https://opensource.com/article/20/2/gnucash
|
||||
[6]: https://en.wikipedia.org/wiki/Envelope_system
|
||||
[7]: https://en.wikipedia.org/wiki/Quicken_Interchange_Format
|
||||
[8]: https://opensource.com/sites/default/files/uploads/envelope-add-account.png (Adding an account in Envelope)
|
||||
[9]: https://opensource.com/sites/default/files/uploads/envelope-entering-transaction.png (Entering a transaction in Envelope)
|
||||
[10]: https://appcenter.elementary.io/com.github.philip-scott.notes-up/
|
||||
[11]: https://opensource.com/article/18/12/taking-notes-standard-notes
|
||||
[12]: https://opensource.com/sites/default/files/uploads/notes-up-main-window.png (Notes-Up)
|
||||
[13]: https://opensource.com/sites/default/files/uploads/notes-up-taking-note.png (Taking notes in Notes-Up)
|
||||
[14]: https://plaintextproject.online
|
||||
[15]: https://opensource.com/article/20/1/open-source-to-do-list
|
||||
[16]: https://appcenter.elementary.io/com.github.lainsce.yishu/
|
||||
[17]: https://opensource.com/sites/default/files/uploads/yishu-task-list.png (Yishu)
|
||||
[18]: https://opensource.com/sites/default/files/uploads/yishu-add-task.png (Adding a task in Yishu)
|
||||
[19]: https://weeklymusings.net/weekly-musings-025
|
||||
[20]: https://appcenter.elementary.io/com.github.matfantinel.reminduck/
|
||||
[21]: https://opensource.com/sites/default/files/uploads/reminduck.png (Reminduck)
|
||||
[22]: https://opensource.com/sites/default/files/uploads/remiunduck-reminders-list.png (Reminduck reminders)
|
||||
[23]: https://opensource.com/sites/default/files/uploads/reminduck-notification.png (Reminduck notification)
|
||||
[24]: https://opensource.com/article/19/8/markdown-beginners-cheat-sheet
|
||||
[25]: https://appcenter.elementary.io/com.github.lainsce.quilter/
|
||||
[26]: https://opensource.com/sites/default/files/uploads/quilter.png (Quilter)
|
||||
[27]: https://opensource.com/sites/default/files/uploads/quilter-editing.png (Quilter)
|
||||
@@ -0,0 +1,219 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (qianmingtian)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Install and Use Wireshark on Ubuntu Linux)
|
||||
[#]: via: (https://itsfoss.com/install-wireshark-ubuntu/)
|
||||
[#]: author: (Community https://itsfoss.com/author/itsfoss/)
|
||||
|
||||
Install and Use Wireshark on Ubuntu Linux
|
||||
======
|
||||
|
||||
_**Brief: You’ll learn to install the latest Wireshark on Ubuntu and other Ubuntu-based distribution in this tutorial. You’ll also learn how to run Wireshark without sudo and how to set it up for packet sniffing.**_
|
||||
|
||||
[Wireshark][1] is a free and open-source network protocol analyzer widely used around the globe.
|
||||
|
||||
With Wireshark, you can capture incoming and outgoing packets of a network in real-time and use it for network troubleshooting, packet analysis, software and communication protocol development, and many more.
|
||||
|
||||
It is available on all major desktop operating systems like Windows, Linux, macOS, BSD and more.
|
||||
|
||||
In this tutorial, I will guide you to install Wireshark on Ubuntu and other Ubuntu-based distributions. I’ll also show a little about setting up and configuring Wireshark to capture packets.
|
||||
|
||||
### Installing Wireshark on Ubuntu based Linux distributions
|
||||
|
||||
![][2]
|
||||
|
||||
Wireshark is available on all major Linux distributions. You should check out the [official installation instructions][3]. because in this tutorial, I’ll focus on installing the latest Wireshark version on Ubuntu-based distributions only.
|
||||
|
||||
Wireshark is available in the Universe repository of Ubuntu. You can [enable universe repository][4] and then install it like this:
|
||||
|
||||
```
|
||||
sudo add-apt-repository universe
|
||||
sudo apt install wireshark
|
||||
```
|
||||
|
||||
One slight problem in this approach is that you might not always get the latest version of Wireshark.
|
||||
|
||||
For example, in Ubuntu 18.04, if you [use the apt command][5] to check the available version of Wireshark, it is 2.6.
|
||||
|
||||
```
|
||||
[email protected]:~$ apt show wireshark
|
||||
Package: wireshark
|
||||
Version: 2.6.10-1~ubuntu18.04.0
|
||||
Priority: optional
|
||||
Section: universe/net
|
||||
Origin: Ubuntu
|
||||
Maintainer: Balint Reczey <[email protected]>
|
||||
```
|
||||
|
||||
However, [Wireshark 3.2 stable version][6] has been released months ago. New release brings new features, of course.
|
||||
|
||||
So, what do you do in such case? Thankfully, Wiresshark developers provide an official PPA that you can use to install the latest stable version of Wireshark on Ubuntu and other Ubuntu-based distributions.
|
||||
|
||||
I hope you are acquainted with PPA. If not, please [read our excellent guide on PPA to understand it completely][7].
|
||||
|
||||
Open a terminal and use the following commands one by one:
|
||||
|
||||
```
|
||||
sudo add-apt-repository ppa:wireshark-dev/stable
|
||||
sudo apt update
|
||||
sudo apt install wireshark
|
||||
```
|
||||
|
||||
Even if you have an older version of Wireshark installed, it will be updated to the newer version.
|
||||
|
||||
While installing, you will be asked whether to allow non-superusers to capture packets. Select Yes to allow and No to restrict non-superusers to capture packets & finish the installation.
|
||||
|
||||
### Running Wireshark without sudo
|
||||
|
||||
If you have selected **No** in the previous installation, then run the following command as root:
|
||||
|
||||
```
|
||||
sudo dpkg-reconfigure wireshark-common
|
||||
```
|
||||
|
||||
And select **Yes** by pressing the tab key and then using enter key:
|
||||
|
||||
![][8]
|
||||
|
||||
Since you have allowed the non-superuser to capture packets, you have to add the user to wireshark group. Use the [usermod command][9] to add yourself to the wireshark group.
|
||||
|
||||
```
|
||||
sudo usermod -aG wireshark $(whoami)
|
||||
```
|
||||
|
||||
Finally, [restart your Ubuntu system][10] to make the necessary changes to your system.
|
||||
|
||||
Trivia
|
||||
|
||||
First released in 1998, Wireshark was initially known as Ethereal. Developers had to change its name to Wireshark in 2006 due to trademark issues.
|
||||
|
||||
### Starting Wireshark
|
||||
|
||||
Launching Wireshark application can be done from the application launcher or the CLI.
|
||||
|
||||
To start from CLI, just type **wireshark** on your console:
|
||||
|
||||
```
|
||||
wireshark
|
||||
```
|
||||
|
||||
From **GUI**, search for Wireshark application on the search bar and hit enter.
|
||||
|
||||
![][11]
|
||||
|
||||
Now let’s play with Wireshark.
|
||||
|
||||
### Capturing packets using Wireshark
|
||||
|
||||
When you start Wireshark, you will see a list of interfaces that you can use to capture packets to and from.
|
||||
|
||||
There are many types of interfaces available which you can monitor using Wireshark such as, Wired, External devices, etc. According to your preference, you can choose to show specific types of interfaces in the welcome screen from the marked area in the given image below.
|
||||
|
||||
![Select interface][12]
|
||||
|
||||
For instance, I listed only the **Wired** network interfaces.
|
||||
|
||||
![][13]
|
||||
|
||||
Next, to start capturing packets, you have to select the interface (which in my case is ens33) and click on the **Start capturing packets** icon as marked in the image below.
|
||||
|
||||
![Start capturing packets with Wireshark][14]
|
||||
|
||||
You can also capture packets to and from multiple interfaces at the same time. Just press and hold the **CTRL** button while clicking on the interfaces that you want to capture to and from and then hit the **Start capturing packets** icon as marked in the image below.
|
||||
|
||||
![][15]
|
||||
|
||||
Next, I tried using **ping google.com** command in the terminal and as you can see, many packets were captured.
|
||||
|
||||
![Captured packets][16]
|
||||
|
||||
Now you can select on any packet to check that particular packet. After clicking on a particular packet you can see the information about different layers of TCP/IP Protocol associated with it.
|
||||
|
||||
![Packet info][17]
|
||||
|
||||
You can also see the RAW data of that particular packet at the bottom as shown in the image below.
|
||||
|
||||
![Check RAW data in the captured packets][18]
|
||||
|
||||
This is why end-to-end encryption is important
|
||||
|
||||
Imagine you are logging into a website that doesn’t use HTTPS. Anyone on the same network as you can sniff the packets and see the user name and password in the RAW data.
|
||||
This is why most chat applications use end to end encryption and most websites these days use https (instead of http).
|
||||
|
||||
#### Stopping packet capture in Wireshark
|
||||
|
||||
You can click on the red icon as marked in the given image to stop capturing Wireshark packets.
|
||||
|
||||
![Stop packet capture in Wireshark][19]
|
||||
|
||||
#### Save captured packets to a file
|
||||
|
||||
You can click on the marked icon in the image below to save captured packets to a file for future use.
|
||||
|
||||
![Save captured packets by Wireshark][20]
|
||||
|
||||
**Note**: _Output can be exported to XML, PostScript®, CSV, or plain text._
|
||||
|
||||
Next, select a destination folder, and type the file name and click on **Save**.
|
||||
Then select the file and click on **Open**.
|
||||
|
||||
![][21]
|
||||
|
||||
Now you can open and analyze the saved packets anytime. To open the file, press **\ + o**
|
||||
or go to **File > Open** from Wireshark.
|
||||
|
||||
The captured packets should be loaded from the file.
|
||||
|
||||
![][22]
|
||||
|
||||
### Conclusion
|
||||
|
||||
Wireshark supports many different communication protocols. There are many options and features that provide you the power to capture and analyze the network packets in a unique way. You can learn more about Wireshark from their [official documentation][23].
|
||||
|
||||
I hope this detailed helped you to install Wireshark on Ubuntu. Please let me know your questions and suggestions.
|
||||
|
||||
![][24]
|
||||
|
||||
### Kushal Rai
|
||||
|
||||
A computer science student & Linux and open source lover. He likes sharing knowledge for he believes technology shapes the perception of modern world. Kushal also loves music and photography.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/install-wireshark-ubuntu/
|
||||
|
||||
作者:[Community][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://itsfoss.com/author/itsfoss/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.wireshark.org/
|
||||
[2]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/03/wireshark_ubuntu.png?ssl=1
|
||||
[3]: https://www.wireshark.org/docs/wsug_html_chunked/ChBuildInstallUnixInstallBins.html
|
||||
[4]: https://itsfoss.com/ubuntu-repositories/
|
||||
[5]: https://itsfoss.com/apt-command-guide/
|
||||
[6]: https://www.wireshark.org/news/20191218.html
|
||||
[7]: https://itsfoss.com/ppa-guide/
|
||||
[8]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/03/yes.png?ssl=1
|
||||
[9]: https://linuxhandbook.com/usermod-command/
|
||||
[10]: https://itsfoss.com/schedule-shutdown-ubuntu/
|
||||
[11]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/03/wire.png?ssl=1
|
||||
[12]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/03/interfaces.jpg?ssl=1
|
||||
[13]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/03/intoption.jpg?ssl=1
|
||||
[14]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/03/singleinterface.jpg?ssl=1
|
||||
[15]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/03/selint.jpg?ssl=1
|
||||
[16]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/03/capture.jpg?ssl=1
|
||||
[17]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/03/packetinfo.png?ssl=1
|
||||
[18]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/03/raw.png?ssl=1
|
||||
[19]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/03/stopcapture.png?ssl=1
|
||||
[20]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/03/savepackets.jpg?ssl=1
|
||||
[21]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/03/savename.jpg?ssl=1
|
||||
[22]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/03/openpacket.png?ssl=1
|
||||
[23]: https://www.wireshark.org/docs/https://www.wireshark.org/docs/
|
||||
[24]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/03/kushal_rai.jpg?ssl=1
|
||||
@@ -0,0 +1,190 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Three Ways to Exclude/Hold/Prevent a Specific Package from an apt Upgrade)
|
||||
[#]: via: (https://www.2daygeek.com/debian-ubuntu-exclude-hold-prevent-packages-from-apt-get-upgrade/)
|
||||
[#]: author: (Magesh Maruthamuthu https://www.2daygeek.com/author/magesh/)
|
||||
|
||||
Three Ways to Exclude/Hold/Prevent a Specific Package from an apt Upgrade
|
||||
======
|
||||
|
||||
Sometimes you may accidentally update packages that are not updated due to some application dependency.
|
||||
|
||||
This is always the case during the entire system update or automatic package upgrade process.
|
||||
|
||||
If this happens, it may break the application function.
|
||||
|
||||
This creates a serious problem and you need to spend a lot of time fixing the problem.
|
||||
|
||||
See the following article if you want to **[Exclude Specific Packages from Yum Update][1]**
|
||||
|
||||
How to avoid this kind of situation?
|
||||
|
||||
How do I exclude packages from apt-get update?
|
||||
|
||||
Yes, it can be done using the following three methods on Debian and Ubuntu systems.
|
||||
|
||||
* **[apt-mark Command][2]**
|
||||
* **[dpkg Command][3]**
|
||||
* aptitude Command
|
||||
|
||||
|
||||
|
||||
We will show in detail each.
|
||||
|
||||
### Method-1: How to Exclude Packages Update on Debian/Ubuntu System Using the apt-mark Command
|
||||
|
||||
The apt-mark is used to mark/unmark a package as being automatically installed.
|
||||
|
||||
The Hold option is used to mark a package as blocked, which prevents the package from being automatically installed, upgraded, or removed.
|
||||
|
||||
The unhold option is used to cancel a previously set hold on a package to allow all actions to be repeated.
|
||||
|
||||
Run the following command to hold the given package using the **apt-mark** command.
|
||||
|
||||
```
|
||||
$ sudo apt-mark hold nano
|
||||
nano set on hold.
|
||||
```
|
||||
|
||||
Once you have hold some packages, run the following apt-mark command to view them.
|
||||
|
||||
```
|
||||
$ sudo apt-mark showhold
|
||||
nano
|
||||
```
|
||||
|
||||
This will show that the **“nano”** package will not be upgraded when you perform a full system update.
|
||||
|
||||
```
|
||||
$ sudo apt update
|
||||
|
||||
Reading package lists… Done
|
||||
Building dependency tree
|
||||
Reading state information… Done
|
||||
Calculating upgrade… Done
|
||||
The following packages have been kept back:
|
||||
nano
|
||||
0 upgraded, 0 newly installed, 0 to remove and 1 not upgraded.
|
||||
```
|
||||
|
||||
Run the following command to unhold the “nano” package using the apt-mark command.
|
||||
|
||||
```
|
||||
$ sudo apt-mark unhold nano
|
||||
Canceled hold on nano.
|
||||
```
|
||||
|
||||
### Method-2: How to Exclude Packages Update on Debian/Ubuntu System Using the dpkg Command
|
||||
|
||||
The dpkg command is a CLI tool to install, build, remove and manage Debian packages. The primary and more user-friendly front-end for dpkg is aptitude.
|
||||
|
||||
Run the following command to block a given package using the dpkg command.
|
||||
|
||||
**Syntax:**
|
||||
|
||||
```
|
||||
$ echo "package_name hold" | sudo dpkg --set-selections
|
||||
```
|
||||
|
||||
Run the below dpkg command to hold the **“apache2”** package.
|
||||
|
||||
```
|
||||
$ echo "apache2 hold" | sudo dpkg --set-selections
|
||||
```
|
||||
|
||||
Once you have hold some packages, run the following command to view them.
|
||||
|
||||
```
|
||||
$ sudo dpkg --get-selections | grep "hold"
|
||||
apache2 hold
|
||||
```
|
||||
|
||||
It will show that the **“apache2”** package will not be upgraded when you perform a full system update.
|
||||
|
||||
```
|
||||
$ sudo apt update
|
||||
|
||||
Reading package lists… Done
|
||||
Building dependency tree
|
||||
Reading state information… Done
|
||||
Calculating upgrade… Done
|
||||
The following packages have been kept back:
|
||||
apache2
|
||||
0 upgraded, 0 newly installed, 0 to remove and 1 not upgraded.
|
||||
```
|
||||
|
||||
Run the following command to unhold the given package using the dpkg command.
|
||||
|
||||
**Syntax:**
|
||||
|
||||
```
|
||||
$ echo "package_name install" | sudo dpkg --set-selections
|
||||
```
|
||||
|
||||
Run the following command to unhold the “apache2” package using the dpkg command.
|
||||
|
||||
```
|
||||
$ echo "apache2 install" | sudo dpkg --set-selections
|
||||
```
|
||||
|
||||
### Method-3: How to Exclude Packages Update on Debian/Ubuntu System Using the aptitude Command
|
||||
|
||||
The aptitude command is a text-based package management interface to the Debian and it’s derivative.
|
||||
|
||||
It allows the user to view a list of packages and to perform package management tasks such as installing, upgrading, and removing packages. Actions may be performed from a visual interface or from the command-line.
|
||||
|
||||
Run the following command to hold the given package using the aptitude command.
|
||||
|
||||
```
|
||||
$ sudo aptitude hold python3
|
||||
```
|
||||
|
||||
Once you have hold some packages, run the following aptitude command to view them.
|
||||
|
||||
```
|
||||
$ sudo dpkg --get-selections | grep "hold"
|
||||
or
|
||||
$ sudo apt-mark showhold
|
||||
|
||||
python3
|
||||
```
|
||||
|
||||
This will show that the **“python3”** package will not be upgraded when you perform a full system update.
|
||||
|
||||
```
|
||||
$ sudo apt update
|
||||
|
||||
Reading package lists… Done
|
||||
Building dependency tree
|
||||
Reading state information… Done
|
||||
Calculating upgrade… Done
|
||||
The following packages have been kept back:
|
||||
python3
|
||||
0 upgraded, 0 newly installed, 0 to remove and 1 not upgraded.
|
||||
```
|
||||
|
||||
Run the following command to unhold the **“python3”** package using the apt-mark command.
|
||||
|
||||
```
|
||||
$ sudo aptitude unhold python3
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.2daygeek.com/debian-ubuntu-exclude-hold-prevent-packages-from-apt-get-upgrade/
|
||||
|
||||
作者:[Magesh Maruthamuthu][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://www.2daygeek.com/author/magesh/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.2daygeek.com/redhat-centos-yum-update-exclude-specific-packages/
|
||||
[2]: https://www.2daygeek.com/apt-get-apt-cache-command-examples-manage-packages-debian-ubuntu-systems/
|
||||
[3]: https://www.2daygeek.com/dpkg-command-to-manage-packages-on-debian-ubuntu-linux-mint-systems/
|
||||
Reference in New Issue
Block a user