Skip to content

Commit

Permalink
windows support
Browse files Browse the repository at this point in the history
  • Loading branch information
skshetry committed Feb 19, 2024
1 parent a506406 commit 7d6365f
Show file tree
Hide file tree
Showing 10 changed files with 139 additions and 57 deletions.
8 changes: 7 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,16 @@ env:
jobs:
ci:
name: Check
runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
- run: cargo fmt --all --check
- run: cargo clippy --all-targets --all-features
- run: cargo test
- run: cargo build --verbose
- run: cargo build --release --verbose
- run: cargo build --profile dist --verbose
44 changes: 32 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,14 @@ ignore = "0.4.22"
itertools = "0.12.1"
env_logger = "0.11.2"
log = "0.4.20"
uzers = "0.11.3"
config = "0.14.0"
serde_derive = "1.0.196"
directories = "5.0.1"
git2 = { version = "0.18.2", default-features = false }
whoami = "1.4.1"

[target.'cfg(windows)'.dependencies]
file-id = "0.2.1"

[dev-dependencies]
tempfile = "3.10.0"
Expand Down Expand Up @@ -67,7 +70,7 @@ cargo-dist-version = "0.10.0"
# The installers to generate for each app
installers = ["shell", "powershell", "msi"]
# Target platforms to build apps for (Rust target-triple syntax)
targets = ["aarch64-apple-darwin", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", "x86_64-unknown-linux-musl"]
targets = ["aarch64-apple-darwin", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", "x86_64-unknown-linux-musl", "x86_64-pc-windows-msvc"]
# CI backends to support
ci = ["github"]
# Publish jobs to run in CI
Expand Down
39 changes: 34 additions & 5 deletions src/build.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
use crate::fsutils;
use crate::fsutils::{compute_checksum, size_from_meta};
use crate::hash::file_md5;
use crate::objects::{Object, Tree, TreeEntry};
use crate::odb::Odb;
use crate::state::{State, StateHash, StateValue};
use crate::timeutils::unix_time;
use ignore;
use ignore::gitignore::Gitignore;
use jwalk::{Parallelism, WalkDir};
use log::debug;
use rayon::prelude::*;
use std::fs;
use std::os::unix::fs::MetadataExt;
use std::path::{Path, PathBuf};
use std::time::Instant;
use std::{fs, u128};
struct FileInfo {
checksum: String,
path: PathBuf,
Expand All @@ -20,9 +20,38 @@ struct FileInfo {

impl FileInfo {
fn from_metadata(path: &Path, meta: &fs::Metadata) -> Self {
let ut = unix_time(meta.modified().unwrap()).unwrap();
let ino: u128 = {
#[cfg(unix)]
{
use std::os::unix::fs::MetadataExt;
u128::from(meta.ino())
}

#[cfg(windows)]
{
use file_id::{get_file_id, FileId};
match get_file_id(path).unwrap() {
FileId::LowRes {
volume_serial_number: _,
file_index,
} => u128::from(file_index),
FileId::HighRes {
volume_serial_number: _,
file_id: id,
} => id,
FileId::Inode {
device_id: _,
inode_number,
} => u128::from(inode_number),
}
}
};
let size = size_from_meta(meta);
let checksum = compute_checksum(ut, ino, size);
Self {
checksum: fsutils::checksum_from_metadata(meta),
size: meta.size(),
checksum,
size,
path: path.to_path_buf(),
}
}
Expand Down
35 changes: 18 additions & 17 deletions src/fsutils.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
use crate::hash::md5;
use core::panic;
use std::fs;
use std::os::unix::fs::{MetadataExt, PermissionsExt};
use std::path::PathBuf;
use std::path::{Path, PathBuf};

pub fn checksum_from_metadata(meta: &fs::Metadata) -> String {
#[allow(clippy::cast_precision_loss)]
let m = meta.mtime() as f64 + (meta.mtime_nsec() as f64 / 1_000_000_000f64);
pub fn compute_checksum(ut: f64, ino: u128, size: u64) -> String {
let st = "([".to_owned()
+ &meta.ino().to_string()
+ &ino.to_string()
+ ", "
+ &m.to_string()
+ &ut.to_string()
+ ", "
+ &meta.size().to_string()
+ &size.to_string()
+ "],)";
let hash = md5(&mut st.as_bytes());
u128::from_str_radix(&hash, 16).unwrap().to_string()
}

pub fn checksum(path: &PathBuf) -> String {
let meta = fs::metadata(path).unwrap();
checksum_from_metadata(&meta)
#[cfg(unix)]
pub fn size_from_meta(meta: &fs::Metadata) -> u64 {
use std::os::unix::fs::MetadataExt;
meta.size()
}

pub fn size(path: PathBuf) -> u64 {
let meta = fs::metadata(path).unwrap();
meta.size()
#[cfg(windows)]
pub fn size_from_meta(meta: &fs::Metadata) -> u64 {
use std::os::windows::fs::MetadataExt;
meta.file_size()
}

pub fn transfer_file(from: &PathBuf, to: &PathBuf) {
Expand All @@ -33,7 +33,8 @@ pub fn transfer_file(from: &PathBuf, to: &PathBuf) {
.unwrap_or_else(|_| panic!("transfer failed: {from:?} {to:?}"));
}

pub fn protect_file(path: &PathBuf) {
let permission = fs::Permissions::from_mode(0o444);
fs::set_permissions(path, permission).unwrap_or_default();
pub fn protect_file(path: &Path) {
if let Ok(m) = path.metadata() {
m.permissions().set_readonly(true);
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub mod odb;
pub mod repo;
pub mod state;
pub mod status;
pub mod timeutils;
pub mod transfer;

pub use build::build;
Expand Down
22 changes: 20 additions & 2 deletions src/objects.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use crate::hash::md5;
use crate::json_format;
use serde::{Deserialize, Serialize};
use itertools::Itertools;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::convert::From;
use std::error::Error;
use std::fs::File;
use std::io::BufReader;
use std::path::PathBuf;
use std::path::{Path, PathBuf};

#[derive(Clone)]
pub enum Object {
Expand All @@ -17,6 +18,7 @@ pub type HashFile = String;

#[derive(Deserialize, Clone, PartialEq, Debug, PartialOrd, Ord, Eq)]
pub struct TreeEntry {
#[serde(deserialize_with = "posixstr_to_ospath")]
pub relpath: PathBuf,
#[serde(rename = "md5")]
pub oid: String,
Expand All @@ -27,6 +29,7 @@ pub struct TreeEntry {
struct TreeEntrySerializer {
#[serde(rename = "md5")]
pub oid: String,
#[serde(serialize_with = "posixify_path")]
pub relpath: PathBuf,
}

Expand Down Expand Up @@ -54,6 +57,21 @@ impl Serialize for TreeEntry {
}
}

fn posixify_path<S>(x: &Path, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
s.serialize_str(&x.iter().map(|p| p.to_str().unwrap()).join("/"))
}

fn posixstr_to_ospath<'de, D>(deserializer: D) -> Result<PathBuf, D::Error>
where
D: Deserializer<'de>,
{
let s: &str = Deserialize::deserialize(deserializer)?;
Ok(s.split('/').collect())
}

impl Tree {
pub fn serialize(&self) -> serde_json::Result<String> {
// make it compatible with `json.dumps()` separator
Expand Down
20 changes: 12 additions & 8 deletions src/repo.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::ffi::OsString;
use std::os::unix::fs::MetadataExt;
use std::path::{Path, PathBuf};

use log::debug;
Expand All @@ -8,6 +7,7 @@ use crate::config::Config;
use crate::hash::md5;
use crate::odb::Odb;
use crate::state::State;
use crate::timeutils::unix_time;
use std::error::Error;
use std::fs;
use std::{env, io};
Expand All @@ -32,25 +32,23 @@ fn btime(tmp_dir: &Path) -> Result<f64, io::Error> {

match result {
Ok(()) => match fs::metadata(btime) {
#[allow(clippy::cast_precision_loss)]
Ok(meta) => Ok(meta.mtime() as f64 + (meta.mtime_nsec() as f64 / 1_000_000_000f64)),
Ok(meta) => Ok(unix_time(meta.modified()?).unwrap()),
Err(e) => Err(e),
},
Err(e) => Err(e),
}
}

#[cfg(unix)]
fn db_dirname(root: &Path, tmp_dir: &Path) -> String {
use std::os::unix::ffi::OsStrExt;
let btime = btime(tmp_dir).unwrap();
let user = uzers::get_current_username().unwrap();
let user = whoami::username();
let dvc_major = 3;
let salt = 2;
let salt = 0;

let mut st: OsString = "('".into();
st.push(root.as_os_str());
st.push("', ");
st.push("None, "); // subdir
st.push(btime.to_string());
st.push(", '");
st.push(user);
Expand All @@ -60,7 +58,7 @@ fn db_dirname(root: &Path, tmp_dir: &Path) -> String {
st.push(salt.to_string());
st.push(")");

md5(&mut st.as_bytes())
md5(&mut st.as_encoded_bytes())
}

#[cfg(not(any(
Expand All @@ -73,6 +71,12 @@ fn db_dirs() -> PathBuf {
"/var/tmp/dvc/repo".into()
}

#[cfg(target_os = "windows")]
fn db_dirs() -> PathBuf {
Path::new(&env::var("CSIDL_COMMON_APPDATA").unwrap_or("C:/ProgramData/iterative/dvc".into()))
.to_owned()
}

#[cfg(target_os = "macos")]
fn db_dirs() -> PathBuf {
"/Library/Caches/dvc/repo".into()
Expand Down
Loading

0 comments on commit 7d6365f

Please sign in to comment.