Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
- name: Setup Rust toolchain
run: ./ci/install-rust.sh && rustup component add rustfmt
- name: Check style
run: ./ci/style.sh
run: ./ci/style.py

clippy:
name: Clippy on ${{ matrix.os }}
Expand Down
1 change: 0 additions & 1 deletion src/rustfmt.toml → .rustfmt.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# Note that there is a separate top-level configuration for everything else
edition = "2021"
error_on_line_overflow = true
group_imports = "StdExternalCrate"
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ We have two automated tests running on
- `cd libc-test && cargo test`
- Use the `skip_*()` functions in `build.rs` if you really need a workaround.
2. Style checker
- [`./ci/style.sh`](https://github.com/rust-lang/libc/blob/main/ci/style.sh)
- [`./ci/style.py`](https://github.com/rust-lang/libc/blob/main/ci/style.py)

## Breaking change policy

Expand Down
10 changes: 8 additions & 2 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
use std::process::{Command, Output};
use std::{env, str};
use std::process::{
Command,
Output,
};
use std::{
env,
str,
};

// List of cfgs this build script is allowed to set. The list is needed to support check-cfg, as we
// need to know all the possible cfgs that this script will set. If you need to set another cfg
Expand Down
10 changes: 8 additions & 2 deletions ci/ios/deploy_and_run_on_ios_simulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,17 @@
// (https://github.com/snipsco/dinghy): cargo dinghy install, then cargo dinghy
// test.

use std::fs::{self, File};
use std::fs::{
self,
File,
};
use std::io::Write;
use std::path::Path;
use std::process::Command;
use std::{env, process};
use std::{
env,
process,
};

macro_rules! t {
($e:expr) => {
Expand Down
5 changes: 4 additions & 1 deletion ci/runtest-android.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use std::env;
use std::path::{Path, PathBuf};
use std::path::{
Path,
PathBuf,
};
use std::process::Command;

fn main() {
Expand Down
165 changes: 165 additions & 0 deletions ci/style.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
#!/usr/bin/env python3

import os
import re
import subprocess as sp
import sys

from difflib import unified_diff
from glob import iglob
from pathlib import Path


FMT_DIRS = ["src", "ci"]
IGNORE_FILES = [
# Too much special syntax that we don't want to format
"src/macros.rs"
]


def main():
# if `CI` is set, do a check rather than overwriting
check_only = os.getenv("CI") is not None
run(["rustfmt", "-V"])

fmt_files = []
for dir in FMT_DIRS:
fmt_files.extend(iglob(f"{dir}/**/*.rs", recursive=True))

for file in fmt_files:
if file in IGNORE_FILES:
continue
fmt_one(Path(file), check_only)

# Run once from workspace root to get everything that wasn't handled as an
# individual file.
if check_only:
run(["cargo", "fmt", "--check"])
else:
run(["cargo", "fmt"])

for file in iglob("libc-test/semver/*.txt"):
check_semver_file(Path(file))

# Style tests
run(
[
"cargo",
"test",
"--manifest-path=libc-test/Cargo.toml",
"--test=style",
"--",
"--nocapture",
]
)

try:
run(["shellcheck", "--version"])
except sp.CalledProcessError:
eprint("ERROR: shellcheck not found")
exit(1)

for file in iglob("**/*.sh", recursive=True):
run(["shellcheck", file])


def fmt_one(fpath: Path, check_only: bool):
eprint(f"Formatting {fpath}")
text = fpath.read_text()

# Rustfmt doesn't format the bodies of `{ ... }` macros, which is most of `libc`. To
# make things usable, we do some hacks to replace macros with some kind of
# alternative syntax that gets formatted about how we want, then reset the changes
# after formatting.

# Turn all braced macro `foo! { /* ... */ }` invocations into
# `fn foo_fmt_tmp() { /* ... */ }`, since our macro bodies are usually valid in
# a function context.
text = re.sub(r"(?!macro_rules)\b(\w+)!\s*\{", r"fn \1_fmt_tmp() {", text)

# Replace `if #[cfg(...)]` within `cfg_if` with `if cfg_tmp!([...])` which
# `rustfmt` will format. We put brackets within the parens so it is easy to
# match (trying to match parentheses would catch the first closing `)` which
# wouldn't be correct for something like `all(any(...), ...)`).
text = re.sub(r"if #\[cfg\((.*?)\)\]", r"if cfg_tmp!([\1])", text, flags=re.DOTALL)

# The `c_enum!` macro allows anonymous enums without names, which isn't valid
# syntax. Replace it with a dummy name.
text = re.sub(r"enum #anon\b", r"enum _fmt_anon", text)

# Invoke rustfmt passing via stdin/stdout so we don't need to write the file. Exits
# on failure.
cmd = ["rustfmt", "--config-path=.rustfmt.toml"]
if check_only:
res = check_output(cmd + ["--check"], input=text)

# Unfortunately rustfmt on stdin always completes with 0 exit code even if
# there are errors, so we need to pick between writing the file to disk or
# relying on empty stdout to indicate success.
# <https://github.com/rust-lang/rustfmt/issues/5376>.
if len(res) == 0:
return
eprint(f"ERROR: File {fpath} is not properly formatted")
print(res)
exit(1)
else:
text = check_output(cmd, input=text)

# Restore all changes in the formatted text
text = re.sub(r"fn (\w+)_fmt_tmp\(\)", r"\1!", text)
text = re.sub(r"cfg_tmp!\(\[(.*?)\]\)", r"#[cfg(\1)]", text, flags=re.DOTALL)
text = re.sub(r"enum _fmt_anon", r"enum #anon", text)

# And write the formatted file back
fpath.write_text(text)


def check_semver_file(fpath: Path):
if "TODO" in str(fpath):
eprint(f"Skipping semver file {fpath}")
return

eprint(f"Checking semver file {fpath}")

text = fpath.read_text()
lines = text.splitlines()
sort = sorted(lines)
if lines != sort:
eprint(f"ERROR: Unsorted semver file {fpath}")
eprint("\n".join(unified_diff(lines, sort, lineterm="")))
exit(1)

duplicates = []
seen = set()
for line in lines:
if line in seen:
duplicates.append(line)
seen.add(line)

if len(duplicates) > 0:
eprint(f"ERROR: Duplicates in semver file {fpath}")
eprint(duplicates)
exit(1)


def check_output(args: list[str], **kw) -> str:
xtrace(args)
return sp.check_output(args, encoding="utf8", text=True, **kw)


def run(args: list[str], **kw) -> sp.CompletedProcess:
xtrace(args)
return sp.run(args, check=True, text=True, **kw)


def xtrace(args: list[str]):
astr = " ".join(args)
eprint(f"+ {astr}")


def eprint(*args, **kw):
print(*args, file=sys.stderr, **kw)


if __name__ == "__main__":
main()
90 changes: 0 additions & 90 deletions ci/style.sh

This file was deleted.

9 changes: 8 additions & 1 deletion ctest-test/src/t1.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
#![allow(dead_code)]

use std::ffi::{c_char, c_double, c_int, c_long, c_uint, c_void};
use std::ffi::{
c_char,
c_double,
c_int,
c_long,
c_uint,
c_void,
};

pub type T1Foo = i32;
pub const T1S: *const c_char = b"foo\0".as_ptr().cast();
Expand Down
5 changes: 4 additions & 1 deletion ctest-test/src/t2.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#![allow(non_camel_case_types)]

use std::ffi::{c_char, c_int};
use std::ffi::{
c_char,
c_int,
};

pub type T2Foo = u32;
pub type T2Bar = u32;
Expand Down
5 changes: 4 additions & 1 deletion ctest-test/tests/all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@

use std::collections::HashSet;
use std::env;
use std::process::{Command, ExitStatus};
use std::process::{
Command,
ExitStatus,
};

/// Create a command that starts in the `target/debug` or `target/release` directory.
fn cmd(name: &str) -> Command {
Expand Down
6 changes: 5 additions & 1 deletion ctest/src/ast/function.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use crate::{Abi, BoxStr, Parameter};
use crate::{
Abi,
BoxStr,
Parameter,
};

/// Represents a function signature defined in Rust.
///
Expand Down
5 changes: 4 additions & 1 deletion ctest/src/ast/static_variable.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::{Abi, BoxStr};
use crate::{
Abi,
BoxStr,
};

/// Represents a static variable in Rust.
///
Expand Down
5 changes: 4 additions & 1 deletion ctest/src/ast/structure.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::{BoxStr, Field};
use crate::{
BoxStr,
Field,
};

/// Represents a struct defined in Rust.
#[derive(Debug, Clone)]
Expand Down
5 changes: 4 additions & 1 deletion ctest/src/ast/union.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::{BoxStr, Field};
use crate::{
BoxStr,
Field,
};

/// Represents a union defined in Rust.
#[derive(Debug, Clone)]
Expand Down
Loading