profile
viewpoint
Vadim Petrochenkov petrochenkov Moscow, Russia

petrochenkov/cargo 0

The Rust package manager

petrochenkov/cbindgen 0

A project for generating C bindings from Rust code

petrochenkov/ccache 0

ccache – a fast compiler cache

petrochenkov/cmake-rs 0

Rust build dependency for running cmake

petrochenkov/dynamorio 0

Dynamic Instrumentation Tool Platform

petrochenkov/highfive 0

Github hooks to provide an encouraging atmosphere for new contributors

petrochenkov/reference 0

The Rust Reference

petrochenkov/rfcs 0

RFCs for changes to Rust

Pull request review commentrust-lang/docs.rs

Add gitlab support

+use crate::error::Result;+use crate::{db::Pool, Config};+use chrono::{DateTime, Utc};+use log::{debug, info, trace, warn};+use once_cell::sync::Lazy;+use postgres::Client;+use regex::Regex;+use reqwest::{+    blocking::Client as HttpClient,+    header::{HeaderMap, HeaderValue, ACCEPT, AUTHORIZATION, USER_AGENT},+};+use serde::Deserialize;+use std::collections::{HashMap, HashSet};+use std::sync::Arc;++const APP_USER_AGENT: &str = concat!(+    env!("CARGO_PKG_NAME"),+    " ",+    include_str!(concat!(env!("OUT_DIR"), "/git_version"))+);++pub fn graphql_update(ids: &[&str]) -> String {+    format!(+        "\+query {{+    projects(ids: {:?}) {{+        ... on Project {{+            id+            nameWithNamespace+            lastActivityAt+            description+            starCount+            forksCount+            openIssuesCount+        }}+    }}+}}",+        ids+    )+}++pub fn graphql_single(path: &str) -> String {+    format!(+        "\+query {{+    project(fullPath: \"{}\") {{+        id+        nameWithNamespace+        lastActivityAt+        description+        starCount+        forksCount+        openIssuesCount+    }}+}}",+        path+    )+}++/// How many repositories to update in a single chunk. Values over 100 are probably going to be+/// rejected by the GraphQL API.+const UPDATE_CHUNK_SIZE: usize = 100;++fn extract_host(url: &str) -> Option<&str> {+    url.split("//")+        .skip(1)+        .next()+        .and_then(|u| u.split('/').next())+}++pub struct GitlabUpdater {+    client: HttpClient,+    pool: Pool,+    config: Arc<Config>,+}++impl GitlabUpdater {+    /// Returns `Err` if the access token has invalid syntax (but *not* if it isn't authorized).+    /// Returns `Ok(None)` if there is no access token.+    pub fn new(config: Arc<Config>, pool: Pool) -> Result<Option<Self>> {+        let mut headers = HeaderMap::new();+        headers.insert(USER_AGENT, HeaderValue::from_static(APP_USER_AGENT));+        headers.insert(ACCEPT, HeaderValue::from_static("application/json"));++        if let Some(token) = &config.gitlab_accesstoken {+            headers.insert(+                AUTHORIZATION,+                HeaderValue::from_str(&format!("token {}", token))?,+            );+        } else {+            return Ok(None);+        }++        let client = HttpClient::builder().default_headers(headers).build()?;++        Ok(Some(GitlabUpdater {+            client,+            pool,+            config,+        }))+    }++    pub fn backfill_repositories(&self) -> Result<()> {+        info!("started backfilling Gitlab repository stats");++        let mut conn = self.pool.get()?;+        let needs_backfilling = conn.query(+            "SELECT releases.id, crates.name, releases.version, releases.repository_url+             FROM releases+             INNER JOIN crates ON (crates.id = releases.crate_id)+             WHERE gitlab_repo IS NULL AND repository_url LIKE '%gitlab.%/%';",+            &[],+        )?;++        let mut missing_urls = HashSet::new();+        for row in &needs_backfilling {+            let id: i32 = row.get("id");+            let name: String = row.get("name");+            let version: String = row.get("version");+            let url: String = row.get("repository_url");++            if missing_urls.contains(&url) {+                eprintln!("{} {} points to a known missing repo", name, version);+            } else if let Some(node_id) = self.load_repository(&mut conn, &url)? {+                conn.execute(+                    "UPDATE releases SET gitlab_repo = $1 WHERE id = $2;",+                    &[&node_id, &id],+                )?;+                info!("backfilled Gitlab repository for {} {}", name, version);+            } else {+                eprintln!("{} {} does not point to a Gitlab repository", name, version);+                missing_urls.insert(url);+            }+        }++        Ok(())+    }++    pub(crate) fn load_repository(&self, conn: &mut Client, url: &str) -> Result<Option<String>> {+        let name = match RepositoryName::from_url(url) {+            Some(name) => name,+            None => return Ok(None),+        };++        // Avoid querying the Gitlab API for repositories we already loaded.+        if let Some(row) = conn.query_opt(+            "SELECT id FROM gitlab_repos WHERE name = $1 LIMIT 1;",+            &[&format!("{}/{}", name.owner, name.repo)],+        )? {+            return Ok(Some(row.get("id")));+        }++        if let Some(url) = extract_host(url) {+            // Fetch the latest information from the Gitlab API.+            let response: GraphResponse<GraphProjectNode> = self.graphql(+                url,+                &graphql_single(&format!("{}/{}", name.owner, name.repo)),+            )?;+            if let Some(repo) = response.data.and_then(|d| d.project) {+                self.store_repository(conn, &repo)?;+                Ok(Some(repo.id))+            } else if let Some(error) = response.errors.get(0) {+                failure::bail!("error loading repository: {}", error.message)+            } else {+                panic!("missing repository but there were no errors!");+            }+        } else {+            failure::bail!("failed to extract host from `{}`", url)+        }+    }++    /// Updates gitlab fields in crates table+    pub fn update_all_crates(&self) -> Result<()> {+        info!("started updating Gitlab repository stats");++        let mut conn = self.pool.get()?;+        let needs_update = conn+            .query(+                "SELECT gitlab_repos.id, releases.repository_url+                 FROM gitlab_repos+                 INNER JOIN releases ON (releases.gitlab_repo = gitlab_repos.id)+                 -- WHERE updated_at < NOW() - INTERVAL '1 day';",+                &[],+            )?+            .into_iter()+            .map(|row| (row.get(0), row.get(1)))+            .collect::<Vec<(String, String)>>();++        if needs_update.is_empty() {+            info!("no Gitlab repository stats needed to be updated");+            return Ok(());+        }++        let mut url_map: HashMap<String, Vec<&str>> = HashMap::new();++        for (chunk, url) in &needs_update {+            if let Some(url) = extract_host(url) {+                url_map.entry(url.to_owned()).or_default().push(chunk);+            } else {+                warn!("Couldn't extract host from `{}`", url);+            }+        }++        for (url, chunks) in &url_map {+            for chunk in chunks.chunks(UPDATE_CHUNK_SIZE) {+                if let Err(err) = self.update_repositories(url, &mut conn, &chunk) {+                    if err.downcast_ref::<RateLimitReached>().is_some() {+                        warn!("rate limit reached, blocked the Gitlab repository stats updater");+                        return Ok(());+                    }+                    return Err(err);+                }+            }+        }++        info!("finished updating Gitlab repository stats");+        Ok(())+    }++    fn update_repositories(&self, url: &str, conn: &mut Client, node_ids: &[&str]) -> Result<()> {+        let response: GraphResponse<GraphNodes<Option<GraphProject>>> =+            self.graphql(url, &graphql_update(node_ids))?;++        // The error is returned *before* we reach the rate limit, to ensure we always have an+        // amount of API calls we can make at any time.+        if let Some(data) = response.data {+            trace!(+                "Gitlab GraphQL rate limit remaining: {}",+                data.rate_limit.remaining+            );+            if data.rate_limit.remaining < self.config.gitlab_updater_min_rate_limit {+                return Err(RateLimitReached.into());+            }++            // When a node is missing (for example if the repository was deleted or made private) the+            // GraphQL API will return *both* a `null` instead of the data in the nodes list and a+            // `NOT_FOUND` error in the errors list.+            for node in &data.nodes {+                if let Some(node) = node {+                    self.store_repository(conn, &node)?;+                }+            }+            for error in &response.errors {+                failure::bail!("error updating repositories: {}", error.message);+            }++            Ok(())+        } else {+            failure::bail!("no data")+        }+    }++    fn graphql<T: serde::de::DeserializeOwned + std::fmt::Debug>(+        &self,+        host: &str,+        query: &str,+    ) -> Result<GraphResponse<T>> {+        eprintln!("doing stuff on {:?}", host);+        eprintln!("+++> {:?}", query);+        // Ok(self+        //     .client+        //     .post(&format!("https://{}/api/graphql", host))+        //     .json(&serde_json::json!({+        //         "query": query,+        //     }))+        //     .send()?+        //     .error_for_status()?+        //     .json()?)+        let tmp = self+            .client+            .post(&format!("https://{}/api/graphql", host))+            .json(&serde_json::json!({+                "query": query,+            }))+            .send()?+            .error_for_status()?;+        eprintln!("---> {:?}", tmp.headers());+        let s: String = tmp.text()?;+        eprintln!("---> {:?}", s);+        panic!("yolo");+    }++    fn store_repository(&self, conn: &mut Client, repo: &GraphProject) -> Result<()> {+        trace!(+            "storing Gitlab repository stats for {}",+            repo.name_with_namespace+        );+        eprintln!("+++> {:?}", repo);+        conn.execute(+            "INSERT INTO gitlab_repos (+                 id, name, description, last_commit, stars, forks, issues, updated_at+             ) VALUES ($1, $2, $3, $4, $5, $6, $7, NOW())+             ON CONFLICT (id) DO+             UPDATE SET+                 name = $2,+                 description = $3,+                 last_commit = $4,+                 stars = $5,+                 forks = $6,+                 issues = $7,+                 updated_at = NOW();",+            &[+                &repo.id,+                &repo.name_with_namespace,+                &repo.description,+                &repo.last_activity_at,+                &(repo.star_count as i32),+                &(repo.forks_count as i32),+                &(repo.open_issues_count as i32),+            ],+        )?;+        Ok(())+    }++    fn delete_repository(&self, conn: &mut Client, id: &str) -> Result<()> {+        trace!("removing Gitlab repository stats for ID {}", id);+        conn.execute("DELETE FROM gitlab_repos WHERE id = $1;", &[&id])?;+        Ok(())+    }+}++#[derive(Debug, Eq, PartialEq)]+struct RepositoryName<'a> {+    owner: &'a str,+    repo: &'a str,+}++impl<'a> RepositoryName<'a> {+    fn from_url(url: &'a str) -> Option<Self> {+        static RE: Lazy<Regex> = Lazy::new(|| {+            Regex::new(r"https?://(\w\.)*gitlab\.(\w\.?)+/(?P<owner>[\w\._-]+)/(?P<repo>[\w\._-]+)")+                .unwrap()+        });++        match RE.captures(url) {+            Some(cap) => {+                let owner = cap.name("owner").expect("missing group 'owner'").as_str();+                let repo = cap.name("repo").expect("missing group 'repo'").as_str();+                Some(Self {+                    owner,+                    repo: repo.strip_suffix(".git").unwrap_or(repo),+                })+            }+            None => None,+        }+    }+}++#[derive(Debug, failure::Fail)]+#[fail(display = "rate limit reached")]+struct RateLimitReached;++#[derive(Debug, Deserialize)]+struct GraphResponse<T> {+    data: Option<T>,+    #[serde(default)]+    errors: Vec<GraphError>,+}++#[derive(Debug, Deserialize)]+struct GraphError {+    message: String,+    locations: Vec<GraphErrorLocation>,+}++#[derive(Debug, Deserialize)]+struct GraphErrorLocation {+    line: u32,+    column: u32,+}++#[derive(Debug, Deserialize)]+struct GraphRateLimit {+    remaining: u32,+}++#[derive(Debug, Deserialize)]+#[serde(rename_all = "camelCase")]+struct GraphNodes<T> {+    nodes: Vec<T>,+    rate_limit: GraphRateLimit,+}++#[derive(Debug, Deserialize)]+struct GraphProjectNode {+    project: Option<GraphProject>,+}++#[derive(Debug, Deserialize)]+#[serde(rename_all = "camelCase")]+struct GraphProject {+    id: String,+    name_with_namespace: String,+    last_activity_at: Option<DateTime<Utc>>,+    description: Option<String>,+    star_count: i64,+    forks_count: i64,+    open_issues_count: i64,+}++#[cfg(test)]+mod test {+    use super::*;++    #[test]+    fn test_repository_name() {+        macro_rules! assert_name {+            ($url:expr => ($owner:expr, $repo: expr)) => {+                assert_eq!(+                    RepositoryName::from_url($url),+                    Some(RepositoryName {+                        owner: $owner,+                        repo: $repo+                    })+                );+            };+        }++        assert_name!("https://gitlab.com/onur/cratesfyi" => ("onur", "cratesfyi"));+        assert_name!("http://gitlab.com/onur/cratesfyi" => ("onur", "cratesfyi"));+        assert_name!("https://www.gitlab.com/onur/cratesfyi" => ("onur", "cratesfyi"));+        assert_name!("http://www.gitlab.com/onur/cratesfyi" => ("onur", "cratesfyi"));+        assert_name!("https://gitlab.com/onur/cratesfyi.git" => ("onur", "cratesfyi"));+        assert_name!("https://gitlab.com/docopt/docopt.rs" => ("docopt", "docopt.rs"));+        assert_name!("https://gitlab.com/onur23cmD_M_R_L_/crates_fy-i" => (+            "onur23cmD_M_R_L_", "crates_fy-i"+        ));+        assert_name!("https://freedesktop.gitlab.org/test/test" => (+            "test", "test"+        ));+        assert_name!("https://gitlab.freedesktop.org/test/test" => (+            "test", "test"+        ));

We must only support gitlab.com, not other GitLab instances. Otherwise someone could publish a crate with an URL that looks like a GitLab instance and extract our API token.

GuillaumeGomez

comment created time in 2 minutes

Pull request review commentrust-lang/docs.rs

Add gitlab support

+use crate::error::Result;+use crate::{db::Pool, Config};+use chrono::{DateTime, Utc};+use log::{debug, info, trace, warn};+use once_cell::sync::Lazy;+use postgres::Client;+use regex::Regex;+use reqwest::{+    blocking::Client as HttpClient,+    header::{HeaderMap, HeaderValue, ACCEPT, AUTHORIZATION, USER_AGENT},+};+use serde::Deserialize;+use std::collections::{HashMap, HashSet};+use std::sync::Arc;++const APP_USER_AGENT: &str = concat!(+    env!("CARGO_PKG_NAME"),+    " ",+    include_str!(concat!(env!("OUT_DIR"), "/git_version"))+);++pub fn graphql_update(ids: &[&str]) -> String {+    format!(+        "\+query {{+    projects(ids: {:?}) {{

We should be using GraphQL variables instead of generating the query dynamically.

GuillaumeGomez

comment created time in 5 minutes

push eventrust-lang/crates.io-index

bors

commit sha a0ebf957bf6babbd3f20bb69b7e7c5d324044222

Updating crate `pea2pea#0.15.0`

view details

push time in a minute

pull request commentrust-lang/rust

Force vec![] to expression position only

:pushpin: Commit c127ed6e97535e4a20873d6cfe4fff364a2b9d9b has been approved by oli-obk,m-ou-se

<!-- @bors r=oli-obk,m-ou-se c127ed6e97535e4a20873d6cfe4fff364a2b9d9b --> <!-- homu: {"type":"Approved","sha":"c127ed6e97535e4a20873d6cfe4fff364a2b9d9b","approver":"oli-obk,m-ou-se"} -->

bugadani

comment created time in 2 minutes

pull request commentrust-lang/rust

Force vec![] to expression position only

Thanks!

@bors r=oli-obk,m-ou-se

bugadani

comment created time in 2 minutes

pull request commentrust-lang/rust

Re-enable all num tests on WASM

:hourglass: Testing commit e10555c65897e32de6621588946caa8f3c33720b with merge 7d3818152d8ab5649d2e5cc6d7851ed7c03055fe... <!-- homu: {"type":"BuildStarted","head_sha":"e10555c65897e32de6621588946caa8f3c33720b","merge_sha":"7d3818152d8ab5649d2e5cc6d7851ed7c03055fe"} -->

Smittyvb

comment created time in 3 minutes

pull request commentrust-lang/rust

Rollup of 13 pull requests

:broken_heart: Test failed - checks-actions <!-- homu: {"type":"BuildFailed","builder_url":"https://github.com/rust-lang-ci/rust/runs/1716662000","builder_name":"checks-actions"} -->

m-ou-se

comment created time in 4 minutes

pull request commentrust-lang/rust

Update rust-analyzer

Could another PR have introduced those errors?

Maybe. I just searched for salsa because of that error message, which popped up a lot in rust-analyzer. Note that it failed on --target arm-unknown-linux-gnueabihf, which might be relevant.

If you think this PR is not the source of the problem, we can just try it again and see what happens.

lnicola

comment created time in 4 minutes

push eventrust-lang/crates.io-index

bors

commit sha 260a1cdd51630db07979784c5b0ea83618bb46be

Updating crate `liverust_lib#0.1.9`

view details

push time in 6 minutes

pull request commentrust-lang/rust

Allow Trait inheritance with cycles on associated types take 2

@jyn514 what commit should I use with rustup-toolchain-install-master? Neither 03c0e58d18d39a8210f559d280998d06d8f160bc nor 455a0e1d91d3f56c4752a9f035e3622c614b7240 work.

spastorino

comment created time in 7 minutes

push eventrust-lang/crates.io-index

bors

commit sha 882ceb679ef47292a63d03ae0d743d91273a2b43

Updating crate `vec_mut_scan#0.4.0`

view details

push time in 9 minutes

pull request commentrust-lang/rust

Rollup of 13 pull requests

:hourglass: Testing commit 94ec9f91cf8d1f6f8931d8e546de0bcbdb982e96 with merge 8f749e7508ffa94a8c4e69e189caf4bd079cc5e2... <!-- homu: {"type":"BuildStarted","head_sha":"94ec9f91cf8d1f6f8931d8e546de0bcbdb982e96","merge_sha":"8f749e7508ffa94a8c4e69e189caf4bd079cc5e2"} -->

m-ou-se

comment created time in 10 minutes

push eventrust-lang/rust

Stein Somers

commit sha d199c5b0206b964abadc8539ad4e959ec8e9413b

BTreeMap: expose new_internal function and sanitize from_new_internal

view details

bors

commit sha d51cf9601c714a8383aecade7c98559dd4831625

Auto merge of #81083 - ssomers:btree_drainy_refactor_1, r=Mark-Simulacrum BTreeMap: expose new_internal function and sanitize from_new_internal `new_internal` is the functional core of the imperative `push_internal_level`, and `from_new_internal` can easily do a proper job instead of returning a half-baked node. r? `@Mark-Simulacrum`

view details

push time in 10 minutes

PR merged rust-lang/rust

BTreeMap: expose new_internal function and sanitize from_new_internal S-waiting-on-bors merged-by-bors

new_internal is the functional core of the imperative push_internal_level, and from_new_internal can easily do a proper job instead of returning a half-baked node.

r? @Mark-Simulacrum

+14 -13

4 comments

2 changed files

ssomers

pr closed time in 10 minutes

pull request commentrust-lang/rust

BTreeMap: expose new_internal function and sanitize from_new_internal

:sunny: Test successful - checks-actions Approved by: Mark-Simulacrum Pushing d51cf9601c714a8383aecade7c98559dd4831625 to master... <!-- homu: {"type":"BuildCompleted","approved_by":"Mark-Simulacrum","base_ref":"master","builders":{"checks-actions":"https://github.com/rust-lang-ci/rust/runs/1716647337"},"merge_sha":"d51cf9601c714a8383aecade7c98559dd4831625"} -->

ssomers

comment created time in 10 minutes

pull request commentrust-lang/rust

Update rust-analyzer

Probably https://github.com/rust-lang/rust/pull/80732.

lnicola

comment created time in 11 minutes

pull request commentrust-lang/rust

Update rust-analyzer

salsa compiles fine with the latest nightly. Could another PR have introduced those errors?

lnicola

comment created time in 12 minutes

pull request commentrust-lang/rust

Rollup of 13 pull requests

:pushpin: Commit 94ec9f91cf8d1f6f8931d8e546de0bcbdb982e96 has been approved by m-ou-se

<!-- @bors r=m-ou-se 94ec9f91cf8d1f6f8931d8e546de0bcbdb982e96 --> <!-- homu: {"type":"Approved","sha":"94ec9f91cf8d1f6f8931d8e546de0bcbdb982e96","approver":"m-ou-se"} -->

m-ou-se

comment created time in 13 minutes

pull request commentrust-lang/rust

Rollup of 13 pull requests

@bors r+ p=13 rollup=never

m-ou-se

comment created time in 13 minutes

PR opened rust-lang/rust

Rollup of 13 pull requests

Successful merges:

  • #79298 (correctly deal with late-bound lifetimes in anon consts)
  • #80031 (resolve: Reject ambiguity built-in attr vs different built-in attr)
  • #80201 (Add benchmark and fast path for BufReader::read_exact)
  • #80635 (Improve diagnostics when closure doesn't meet trait bound)
  • #80765 (resolve: Simplify collection of traits in scope)
  • #80932 (Allow downloading LLVM on Windows and MacOS)
  • #80983 (Remove is_dllimport_foreign_item definition from cg_ssa)
  • #81064 (Support non-stage0 check)
  • #81071 (rustc_parse_format: Fix character indices in find_skips)
  • #81082 (BTreeMap: clean up a few more comments)
  • #81084 (Use Option::map instead of open-coding it)
  • #81095 (Use Option::unwrap_or instead of open-coding it)
  • #81107 (Add NonZeroUn::is_power_of_two)

Failed merges:

r? @ghost @rustbot modify labels: rollup <!-- homu-ignore:start --> Create a similar rollup <!-- homu-ignore:end -->

+803 -334

0 comment

54 changed files

pr created time in 13 minutes

PR closed rust-lang/rust

Rollup of 14 pull requests S-waiting-on-review rollup

Successful merges:

  • #79298 (correctly deal with late-bound lifetimes in anon consts)
  • #80031 (resolve: Reject ambiguity built-in attr vs different built-in attr)
  • #80635 (Improve diagnostics when closure doesn't meet trait bound)
  • #80732 (Allow Trait inheritance with cycles on associated types take 2)
  • #80765 (resolve: Simplify collection of traits in scope)
  • #80865 (Use PlaceRef projection abstractions more consistently in rustc_mir)
  • #80932 (Allow downloading LLVM on Windows and MacOS)
  • #80984 (Update rust-analyzer)
  • #81038 (Update Clippy)
  • #81064 (Support non-stage0 check)
  • #81071 (rustc_parse_format: Fix character indices in find_skips)
  • #81082 (BTreeMap: clean up a few more comments)
  • #81084 (Use Option::map instead of open-coding it)
  • #81095 (Use Option::unwrap_or instead of open-coding it)

Failed merges:

r? @ghost @rustbot modify labels: rollup <!-- homu-ignore:start --> Create a similar rollup <!-- homu-ignore:end -->

+3698 -807

5 comments

189 changed files

m-ou-se

pr closed time in 17 minutes

pull request commentrust-lang/rust

Update rust-analyzer

@bors r-

This failed in https://github.com/rust-lang/rust/pull/81102#issuecomment-761720245

error: could not compile `salsa`

That seems to be a rust-analyzer dependency.

lnicola

comment created time in 17 minutes

push eventrust-lang/rustlings

Abdou Seck

commit sha 0b9220c1fc5ae32438f64bf2f5bf5f47d33e3f3f

Add looks_done method to Exercise to expose a resolution state

view details

Abdou Seck

commit sha 8bbe4ff1385c5c169c90cd3ff9253f9a91daaf8e

feat(cli): Improve the list command with options, and then some 1. `rustlings list` should now display more than just the exercise names. Information such as file paths and exercises statuses should be displayed. The `--paths` option limits the displayed fields to only the path names; while the `--names` option limits the displayed fields to only exercise names. You can also control which exercises are displayed, by using the `--filter` option, or the `--solved` or `--unsolved` flags. Some use cases: - Fetching pending exercise files with the keyword "conversion" to pass to my editor: ```sh vim $(rustlings list --filter "conversion" --paths --unsolved) ``` - Fetching exercise names with keyword "conversion" to pass to `rustlings run`: ```sh for exercise in $(rustlings list --filter "conversion" --names) do rustlings run ${exercise} done ``` 2. This should also fix #465, and will likely fix #585, as well. That bug mentioned in those issues has to do with the way the `watch` command handler fetches the pending exercises. Going forward, the least recently updated exercises along with all the other exercises in a pending state are fetched.

view details

fmoko

commit sha e8d1baa4b50faf038bec7629b559a0735173ee80

Merge pull request #599 from AbdouSeck/improve-list-command feat(cli): Improve the list command with options, and then some

view details

push time in 17 minutes

PR merged rust-lang/rustlings

feat(cli): Improve the list command with options, and then some

The PR is two-fold:

  1. rustlings list should now display more than just the exercise names. Information such as file paths and exercises statuses should be displayed. The --paths option limits the displayed fields to only the path names; while the --names option limits the displayed fields to only exercise names. You can also control which exercises are displayed, by using the --filter option, or the --solved or --unsolved flags.

Sample invocations:

# Display exercises that deal with traits, or enums, or structs.
rustlings list --filter "trait,enum,struct"

# Sample output:
# Name             	Path                                          	Status
# structs1         	exercises/structs/structs1.rs                 	Pending
# structs2         	exercises/structs/structs2.rs                 	Pending
# structs3         	exercises/structs/structs3.rs                 	Pending
# enums1           	exercises/enums/enums1.rs                     	Pending
# enums2           	exercises/enums/enums2.rs                     	Pending
# enums3           	exercises/enums/enums3.rs                     	Pending
# traits1          	exercises/traits/traits1.rs                   	Pending
# traits2          	exercises/traits/traits2.rs                   	Pending

# Display only exercises pending to be solved
rustlings list --unsolved

# Sample output:
# Name             	Path                                          	Status
# structs2         	exercises/structs/structs2.rs                 	Pending
# structs3         	exercises/structs/structs3.rs                 	Pending
# enums1           	exercises/enums/enums1.rs                     	Pending
# enums2           	exercises/enums/enums2.rs                     	Pending
# enums3           	exercises/enums/enums3.rs                     	Pending
# modules1         	exercises/modules/modules1.rs                 	Pending
# modules2         	exercises/modules/modules2.rs                 	Pending
# collections1     	exercises/collections/vec1.rs                 	Pending
# collections2     	exercises/collections/vec2.rs                 	Pending
# collections3     	exercises/collections/hashmap1.rs             	Pending
# collections4     	exercises/collections/hashmap2.rs             	Pending

This portion should also close #281.

Some shell utility use cases:

  • Fetching pending exercise file paths with the keyword "conversion" to pass to my editor:
vim $(rustlings list --filter "conversion" --paths --unsolved)
  • Fetching exercise names with keyword "conversion" to pass to rustlings run:
for exercise in $(rustlings list --filter "conversion" --names)
do
    rustlings run ${exercise}
done
  1. The PR should also fix #465, and will likely fix #585, as well. The bug mentioned in those issues has to do with the way the watch command handler fetches the pending exercises. Going forward, the least recently updated exercises along with all the other exercises in a pending state are fetched.

@fmoko @jrvidal if you've got some time, I'd love an eye on this. If there is anyone else with some experience on (or interest in) the CLI component, please feel free to let me know what you think.

Thanks, Abdou

+207 -20

0 comment

4 changed files

AbdouSeck

pr closed time in 17 minutes

issue closedrust-lang/rustlings

`as_ref_mut` not ran

Hey, First of all, thank you very much for this instructive course, which helped me to get back into rust very fast. I noticed that, when I finished the second-to-last exercise, from_str, that rustlings watch immediately told me that I was finished, although I did not touch as_ref_mut. Do you know why that might be? I am running rustlings 4.1.0 and rustc 1.47.0 Best regards Anton

closed time in 17 minutes

AntonOellerer

issue closedrust-lang/rustlings

Unexpected completion

POC:

  1. Finish exercises in order while rustlings watch.
  2. When the current working exercise is move_semantics2.rs, make a copy of it.
  3. The new file move_semantics2 copy.rs is generated, then rustlings outputs ★ All exercises completed! ★ and exits.

I have not verified the file name in the above process is critical or not. In fact, I am not sure that is an issue ... Maybe I should not do that?

Env:

  • rustc 1.44.1 (c7087fe00 2020-06-17)
  • cargo 1.44.1 (88ba85757 2020-06-11)
  • rustlings 4.0.0

closed time in 17 minutes

Wycers

issue closedrust-lang/rustlings

Follow `rustlings watch` with editor by opening source files in the same order

First of all, thank you so much for rustlings, this is an amazing project! A well thought-out practice test suite is worth a thousand tutorials.

I got lazy from having to close nvim and open it on the next file to keep up with rustlings watch, so I came up with a little kludge:

cd rustlings # local rustlings repo
rg '^path = "' info.toml | rg '"(.*)"' --only-matching --replace='$1' --null | xargs -J {} nvim '{}'

This is the same as typing:

nvim file1 file2 file3 ...

When you do this, nvim opens one file at a time, and you can navigate between them with :previous and :next.

So after passing the tests for one exercise, I delete the // I AM NOT DONE line, then type :wn on nvim, which saves the file (w is for "write") and opens the next one (n).

That's enough keystroke savings for me, but if this sounds like an interesting idea, maybe it could be turned into a rustlings watch editor command that calls $EDITOR in succession with the file that's currently failing rustlings watch, so both can be kept running side by side in sync.

closed time in 17 minutes

agentofuser

pull request commentrust-lang/rust

Fix `unused_unsafe` label with `unsafe_block_in_unsafe_fn

I guess at this point I just as well might.^^ r? @RalfJung

LeSeulArtichaut

comment created time in 21 minutes

push eventrust-lang/crates.io-index

bors

commit sha 531a1c796ae213a321e5f8d9f512e9ff41d84277

Updating crate `minhook-sys#0.1.1`

view details

push time in 24 minutes

pull request commentrust-lang/rust

Force vec![] to expression position only

Apart from the fact that I accidentally committed it, I have no idea. I'll fix it asap, thanks for noticing :)

leave implementation details like this out of the root of the crate.

Fair enough :)

bugadani

comment created time in 25 minutes

more