diff --git a/rust/treedirstate/.cargo/config b/.cargo/config rename from rust/treedirstate/.cargo/config rename to .cargo/config diff --git a/Makefile b/Makefile --- a/Makefile +++ b/Makefile @@ -15,7 +15,8 @@ $(PYTHON) setup.py \ build_py -c -d . \ build_clib \ - build_ext -i + build_ext -i \ + build_rust_ext -i install: $(PYTHON) setup.py $(PURE) install --prefix="$(PREFIX)" --force diff --git a/hgext3rd/rust/__init__.py b/hgext3rd/rust/__init__.py new file mode 100644 --- /dev/null +++ b/hgext3rd/rust/__init__.py @@ -0,0 +1,6 @@ +from __future__ import absolute_import +import pkgutil + +# Indicate that hgext3rd.rust is a namspace package, and other python path +# directories may still be searched for hgext3rd.rust libraries. +__path__ = pkgutil.extend_path(__path__, __name__) diff --git a/treedirstate/__init__.py b/hgext3rd/treedirstate.py rename from treedirstate/__init__.py rename to hgext3rd/treedirstate.py --- a/treedirstate/__init__.py +++ b/hgext3rd/treedirstate.py @@ -27,7 +27,7 @@ import struct import string -from .rusttreedirstate import RustDirstateMap +from hgext3rd.rust.treedirstate import treedirstatemap as rusttreedirstatemap dirstateheader = b'########################treedirstate####' treedirstateversion = 1 @@ -125,7 +125,7 @@ self.copymap = {} self._filename = 'dirstate' - self._rmap = RustDirstateMap(ui, opener) + self._rmap = rusttreedirstatemap(ui, opener) self._treeid = None self._parents = None self._dirtyparents = False diff --git a/rust/treedirstate/Cargo.toml b/rust/treedirstate/Cargo.toml --- a/rust/treedirstate/Cargo.toml +++ b/rust/treedirstate/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "rusttreedirstate" +name = "treedirstate" version = "0.1.0" authors = ["Facebook Source Control Team "] @@ -7,7 +7,7 @@ lto = true [lib] -name = "rusttreedirstate" +name = "treedirstate" crate-type = ["cdylib"] [dependencies] diff --git a/rust/treedirstate/src/lib.rs b/rust/treedirstate/src/lib.rs --- a/rust/treedirstate/src/lib.rs +++ b/rust/treedirstate/src/lib.rs @@ -38,6 +38,7 @@ pub mod filestate; pub mod filestore; #[cfg(not(test))] +#[allow(non_camel_case_types)] pub mod python; pub mod store; pub mod tree; diff --git a/rust/treedirstate/src/python.rs b/rust/treedirstate/src/python.rs --- a/rust/treedirstate/src/python.rs +++ b/rust/treedirstate/src/python.rs @@ -13,11 +13,11 @@ use tree::{Key, KeyRef}; py_module_initializer!( - rusttreedirstate, - initrusttreedirstate, - PyInit_rusttreedirstate, + treedirstate, + inittreedirstate, + PyInit_treedirstate, |py, m| { - m.add_class::(py)?; + m.add_class::(py)?; Ok(()) } ); @@ -36,7 +36,7 @@ ErrorKind::CallbackError(s) } -py_class!(class RustDirstateMap |py| { +py_class!(class treedirstatemap |py| { data repodir: PathBuf; data dirstate: RefCell>; data casefolderid: RefCell>; @@ -45,10 +45,10 @@ _cls, _ui: &PyObject, opener: &PyObject - ) -> PyResult { + ) -> PyResult { let repodir = opener.getattr(py, "base")?.extract::(py)?; let dirstate = Dirstate::new(); - RustDirstateMap::create_instance( + treedirstatemap::create_instance( py, repodir.into(), RefCell::new(dirstate), diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -2,6 +2,7 @@ from distutils.cmd import Command from distutils.core import setup, Extension import distutils +from distutils_rust import RustExtension, BuildRustExt import fnmatch from glob import glob @@ -22,6 +23,25 @@ OPTIMIZATION = "" if iswindows else "-O2" PRODUCEDEBUGSYMBOLS = "/DEBUG:FULL" if iswindows else "-g" +if 'USERUST' in os.environ: + USERUST = int(os.environ['USERUST']) +else: + import subprocess + USERUST = False + try: + cargo_version = subprocess.check_output(['cargo', '--version']).split()[1] + except Exception: + sys.stderr.write("not compiling Rust extensions: cargo is not available\n") + else: + required_cargo_version = '0.21' + if (LooseVersion(cargo_version) >= LooseVersion(required_cargo_version)): + USERUST = True + else: + sys.stderr.write( + "not compiling Rust extensions: cargo is too old " + + "(found %s, need %s or higher)\n" + % (cargo_version, required_cargo_version)) + # whether to use Cython to recompile .pyx to .c/.cpp at build time. # if False, fallback to .c/.cpp in the repo and .pyx files are ignored. # if True, re-compile .c/.cpp from .pyx files, require cython at build time. @@ -496,6 +516,15 @@ for name in fnmatch.filter(files, patten): yield os.path.join(dirname, name) +rust_ext_modules = [] +if USERUST: + rust_ext_modules.extend([ + RustExtension('treedirstate', + package='hgext3rd.rust', + manifest='rust/treedirstate/Cargo.toml', + ), + ]) + setup( name='fbhgext', version='1.0', @@ -510,9 +539,11 @@ packages=packages, install_requires=requires, py_modules=py_modules, - ext_modules = ext_modules, + ext_modules=ext_modules, libraries=libraries, + rust_ext_modules=rust_ext_modules, cmdclass={ 'clean_ext': CleanExtCommand, + 'build_rust_ext': BuildRustExt, } ) diff --git a/treedirstate/Makefile b/treedirstate/Makefile deleted file mode 100644 --- a/treedirstate/Makefile +++ /dev/null @@ -1,44 +0,0 @@ -NAME := rusttreedirstate - -# Cargo's depfiles use full paths, so we must include the full path -# to the rust library. -DIR := $(realpath $(join $(dir $(firstword $(MAKEFILE_LIST))),../rust/treedirstate)) - -MODE ?= release - -ifeq ($(MODE),release) -CARGO_ARGS += --release -endif - -ifeq ($(shell uname),Darwin) -LIBSUFFIX := .dylib -else -LIBSUFFIX := .so -endif - -RUSTLIB := $(DIR)/target/$(MODE)/lib$(NAME)$(LIBSUFFIX) -RUSTDEP := $(DIR)/target/$(MODE)/lib$(NAME).d - -.PHONY: all -all: $(NAME).so - -$(NAME).so: $(RUSTLIB) - cp $< $@ - -$(RUSTLIB): - cd $(DIR) && cargo build $(CARGO_ARGS) - -.PHONY: test -test: - cd $(DIR) && cargo test - -.PHONY: clean -clean: - $(RM) $(NAME).so - cd $(DIR) && cargo clean - -# This pattern rule for Rust source files forces a rebuild if any source file -# is deleted. -$(DIR)/src/%.rs: ; - --include $(RUSTDEP)