Skip to content

Commit 4bfcc31

Browse files
committed
Ruby: support long paths on Windows
1 parent 50ff82f commit 4bfcc31

File tree

2 files changed

+54
-7
lines changed

2 files changed

+54
-7
lines changed

ruby/extractor/src/extractor.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ pub fn extract(
119119
path: &Path,
120120
source: &[u8],
121121
ranges: &[Range],
122-
) -> std::io::Result<()> {
122+
) -> () {
123123
let path_str = format!("{}", path.display());
124124
let span = tracing::span!(
125125
tracing::Level::TRACE,
@@ -150,7 +150,7 @@ pub fn extract(
150150
traverse(&tree, &mut visitor);
151151

152152
parser.reset();
153-
Ok(())
153+
()
154154
}
155155

156156
/// Normalizes the path according the common CodeQL specification. Assumes that

ruby/extractor/src/main.rs

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,53 @@ fn encoding_from_name(encoding_name: &str) -> Option<&(dyn encoding::Encoding +
5656
}
5757
}
5858

59+
/// Convert a user-supplied path to an absolute path, and convert it to a verbatim path on Windows.
60+
fn path_from_string(path: &str) -> PathBuf {
61+
let mut path = PathBuf::from(path);
62+
// make path absolute
63+
if path.is_relative() {
64+
path = std::env::current_dir().unwrap().join(path)
65+
};
66+
let mut components = path.components();
67+
68+
// make Windows paths verbatim (with `\\?\` prefixes) which allow for extended-length paths.
69+
let mut result = match components.next() {
70+
None => unimplemented!("empty path"),
71+
72+
Some(component) => match component {
73+
std::path::Component::Prefix(prefix) => match prefix.kind() {
74+
std::path::Prefix::Disk(drive) => {
75+
let root = format!(r"\\?\{}:\", drive as char);
76+
PathBuf::from(root)
77+
}
78+
std::path::Prefix::UNC(server, share) => {
79+
let mut root = std::ffi::OsString::from(r"\\?\UNC\");
80+
root.push(server);
81+
root.push(r"\");
82+
root.push(share);
83+
PathBuf::from(root)
84+
}
85+
std::path::Prefix::Verbatim(_)
86+
| std::path::Prefix::VerbatimUNC(_, _)
87+
| std::path::Prefix::VerbatimDisk(_)
88+
| std::path::Prefix::DeviceNS(_) => Path::new(&component).to_path_buf(),
89+
},
90+
_ => Path::new(&component).to_path_buf(),
91+
},
92+
};
93+
// remove `.` and `..` components
94+
for component in components {
95+
match component {
96+
std::path::Component::CurDir => continue,
97+
std::path::Component::ParentDir => {
98+
result.pop();
99+
}
100+
_ => result.push(component),
101+
}
102+
}
103+
result
104+
}
105+
59106
fn main() -> std::io::Result<()> {
60107
tracing_subscriber::fmt()
61108
.with_target(false)
@@ -122,15 +169,15 @@ fn main() -> std::io::Result<()> {
122169
let src_archive_dir = matches
123170
.value_of("source-archive-dir")
124171
.expect("missing --source-archive-dir");
125-
let src_archive_dir = PathBuf::from(src_archive_dir);
172+
let src_archive_dir = path_from_string(src_archive_dir);
126173

127174
let trap_dir = matches
128175
.value_of("output-dir")
129176
.expect("missing --output-dir");
130-
let trap_dir = PathBuf::from(trap_dir);
177+
let trap_dir = path_from_string(trap_dir);
131178

132179
let file_list = matches.value_of("file-list").expect("missing --file-list");
133-
let file_list = fs::File::open(file_list)?;
180+
let file_list = fs::File::open(path_from_string(file_list))?;
134181

135182
let language = tree_sitter_ruby::language();
136183
let erb = tree_sitter_embedded_template::language();
@@ -164,7 +211,7 @@ fn main() -> std::io::Result<()> {
164211
&path,
165212
&source,
166213
&[],
167-
)?;
214+
);
168215

169216
let (ranges, line_breaks) = scan_erb(
170217
erb,
@@ -251,7 +298,7 @@ fn main() -> std::io::Result<()> {
251298
&path,
252299
&source,
253300
&code_ranges,
254-
)?;
301+
);
255302
std::fs::create_dir_all(&src_archive_file.parent().unwrap())?;
256303
if needs_conversion {
257304
std::fs::write(&src_archive_file, &source)?;

0 commit comments

Comments
 (0)