Commit Graph

43388 Commits

Author SHA1 Message Date
Mark Thomas
76e9f1518b templatekw: untemplated lists of objects should render sensibly
Summary:
Make template keywords that expand to lists of things that aren't strings, and
don't have a template to render the items in the list, render as the number of
items.

Reviewed By: mitrandir77

Differential Revision: D8161705

fbshipit-source-id: 19ca1cba88c0ce75c0ba358cd7e6f27c7ac61c34
2018-05-25 10:05:41 -07:00
Mark Thomas
c5567be530 templatekw: add test demonstrating bad template expansion
Summary:
The template keyword '{succsandmarkers}', or any template keyword that
represents a list of dicts, does not expand well if used on its own.

This test demonstrates that it gets expanded to the string concatenation of the
object's keys, merged with the mapping dictionary's keys, which is very
meaningless.  Nobody seems to use this, except as a truthy value, but it seems
like bad behaviour.

The keys can come in any order, so the test just matches a long string of
characters.

In a future diff we will make this meaningful: the count of objects.

Reviewed By: mitrandir77

Differential Revision: D8161704

fbshipit-source-id: 78e1b86a64eb887603bd6e58682eb7567f06cbce
2018-05-25 10:05:41 -07:00
Jun Wu
7b9867ac12 crates: pin rand to 0.4 version
Summary:
`rand` 0.5 has too many breaking changes that the code is not ready to
migrate yet. So let's ping rand to 0.4. Ideally all dependencies in
Cargo.toml should avoid using "*". But for now `rand` is the only
troublemaker.

Note `rand 0.4` is a dependency of `quickcheck 0.6.2` so it's available.

Reviewed By: phillco, singhsrb

Differential Revision: D8158406

fbshipit-source-id: 417ae6807a2efc650acb8d82370964fab6531fdb
2018-05-25 09:51:19 -07:00
Jun Wu
7a348e55a9 zstdelta: rust library to use zstd to do delta-ing and compression
Summary:
Using zstd dictionary as the "delta base" can result in overall better and
faster compression (than things like mdiff + zstd, or fossil_delta + zstd).

This diff adds utility functions to do delta generation and application.
It tweaks compression parameters (wlog, hlog) to optimize the "delta-ing"
usecase. It now hardcoded the "fast" strategy (level=1) to have reasonable
speed. We can add other compression levels later if needed.

Reviewed By: jsgf

Differential Revision: D7562908

fbshipit-source-id: 3334059b4abeb8923d603d055bde0bfdc854bc7b
2018-05-25 09:34:34 -07:00
Mark Thomas
b22cc19d0a commitcloud: strip whitespace from tokens
Summary:
If tokens are stored with whitespace around them, sending them as OAuth headers
may fail.  Make sure we strip them.

Reviewed By: mitrandir77

Differential Revision: D8160309

fbshipit-source-id: b403be6b11f25087ebc1ecdbe9a58b7f9dbda2f8
2018-05-25 07:47:00 -07:00
Stanislau Hlebik
cfd7a429ae calculate the time correctly
Summary: Let's calculate it in milliseconds

Reviewed By: mitrandir77

Differential Revision: D8146454

fbshipit-source-id: bdfef9a4fe03c65d2ca76163a24d3ea8e64fc600
2018-05-25 04:35:07 -07:00
Jun Wu
4718c95974 checkheads: add a config to disable it
Summary:
Checkheads is a legacy feature that is less useful in our setups, namely:
- In commit cloud / Mononoke's world, it's intentional to have many heads.
  Pushing a new head is a normal operation that should not be forbidden.
- With remotenames, remotenames performs the check and checkheads is
  redundant, as shown by the added test.

So let's add a config option to turn it off first. Later we can remove the
feature and update all the tests.

Reviewed By: ryanmce

Differential Revision: D8148016

fbshipit-source-id: 71684f20b9ca37902440eae331292679b0feb4c6
2018-05-25 02:47:19 -07:00
Jun Wu
94d3ce2b10 stat: add a new "status" style
Summary:
Make it show "added", "removed", "changed" so it looks similar to the
original commit template.

Reviewed By: singhsrb

Differential Revision: D8158006

fbshipit-source-id: 1a1578bd263e7870c27e7169537e808ffd8add9f
2018-05-25 01:04:07 -07:00
Jun Wu
1a9c3ba3c2 stat: change '{stat}' template keyword to a template function
Summary: This allows the function to optionally take arguments.

Reviewed By: singhsrb

Differential Revision: D8158007

fbshipit-source-id: a1eb89a00694c69d8d76dc4e2f7c0ce99164bcfb
2018-05-25 01:04:07 -07:00
Liubov Dmitrieva
76e4306d8b commitcloud: improve naming and clean up unused code
Reviewed By: singhsrb

Differential Revision: D8154257

fbshipit-source-id: ee3f8652831a450c61c1eb1cdda184d80e24307d
2018-05-24 17:49:20 -07:00
Liubov Dmitrieva
12796cbac0 code fixes to support Rust < 1.26
Summary: This changes to support Scm Daemon on dev machines

Reviewed By: farnz

Differential Revision: D8139892

fbshipit-source-id: b6df53d6ce6615d24822b739d4d1705e0f572660
2018-05-24 12:19:55 -07:00
Liubov Dmitrieva
39ccc28933 Scm Daemon initial implementation
Summary: Scm Daemon initial implementation that currently just listen to Commit Cloud Live Notifications and trigger `hg cloud sync` on notifications

Reviewed By: markbt

Differential Revision: D8119768

fbshipit-source-id: a0d86624fe4b81b3adc89990640916d3da279b8c
2018-05-24 12:19:55 -07:00
Adam Simpkins
7233f0dfb1 update cdatapack utilities to check open success
Summary:
Update cdatapack_dump and cdatapack_get to check the return value from
`open_datapack()` to confirm if they actually successfully opened the file.

Previously these programs would segfault if invoked with a non-existent path.

Reviewed By: quark-zju

Differential Revision: D8131017

fbshipit-source-id: 90800de57430efd176b8e71fa84161f7b288e375
2018-05-24 11:30:48 -07:00
Jun Wu
a6fcceea31 chg: make sure client and server have a matched version
Summary:
Generate a `u64` integer about the "version" at build time, and make chg
client check the version before connecting to the server.

This would ensure a chg client would only connect to a matched version of
the server.

- In setup.py, compute the "versionhash", write it as
  `mercurial.__version__.versionhash`.
- In dispatch.py, `mercurial.__version__` needs to be explicitly loaded
  before forking.
- In commandserver.py, send the versionhash to the client with the "hello"
  message.
- In chg.c, verify the versionhash. If it does not match, unlink the socket
  path and reconnect.

Reviewed By: farnz

Differential Revision: D7978131

fbshipit-source-id: 50acc923e72e40a4f66a96f01a194cf1a57fe832
2018-05-24 09:12:00 -07:00
Mark Thomas
338f309ff2 help: fix wireproto title underline length
Summary:
Mercurial help syntax requires that the line is the same length as the line it
is under.

Reviewed By: mitrandir77

Differential Revision: D8140787

fbshipit-source-id: 460b6e1503d7a42f35b8205376ec6819144d9c0b
2018-05-24 07:19:20 -07:00
Mark Thomas
e41f0630e5 treemanifest: more logging for fetching trees
Summary:
Make the (user-facing) log for prefetching trees say how many commits (or which
commit) it is prefetching for.

When remotefilelog.debug is enabled, print out the manifest identity when
fetching a tree during normal operation.

Reviewed By: quark-zju

Differential Revision: D8056555

fbshipit-source-id: dc0c7bc5c949a0674d5f553661e736bc545134b4
2018-05-24 07:19:20 -07:00
Stanislau Hlebik
b18291438c logging of getfiles requests
Summary:
In previous diff we've added the ability to log wireproto requests.
However getfiles wireproto request is special, because it sends arguments in a different way.

Reviewed By: farnz

Differential Revision: D8097782

fbshipit-source-id: f598acd155e842e90d14a295fc71b1886e5a7fb0
2018-05-24 03:25:23 -07:00
Stanislau Hlebik
6a2de8034d wireproto logging
Summary:
Make it possible to log wireproto requests. It will be used by Mononoke to
replay the traffic sent to hg. It can also be used to analyze what expensive
wireproto requests we have.

Reviewed By: farnz

Differential Revision: D8042236

fbshipit-source-id: 7b2b762a51bcbfad30309d15e58afd99618b7af9
2018-05-24 03:25:23 -07:00
Jun Wu
39bda34869 revert: fix status issue when reverting to non-parent revision
Summary:
When reverting to non-parent revision, the reverted files should be marked
as "need content check" anyway. The code should not depend on the fact the
mtime of the reverted files is usually "fsnow".

Reviewed By: DurhamG

Differential Revision: D8123136

fbshipit-source-id: d602ee06408701c0190c142f1ea4e0ff6247fe62
2018-05-23 16:10:05 -07:00
Jun Wu
03a664afdf revert: add a test showing status could be wrong
Summary: The test explains it.

Reviewed By: DurhamG

Differential Revision: D8123137

fbshipit-source-id: 673dad35e0f917788c8af6eaa2b6ea09508b136a
2018-05-23 16:10:05 -07:00
Liubov Dmitrieva
a1f92a5436 use better practice to pass authorization token in http header
Summary:
The querystring is encrypted with SSL

However, URLs can be stored in web server logs - typically the whole URL of each request is
stored in a server log. This means that any sensitive data in the URL (e.g. a
password) is being saved in clear text on the server

Reviewed By: farnz

Differential Revision: D8075914

fbshipit-source-id: 4eadd362755272414dadad069e7ba04db7a01ee8
2018-05-23 12:52:54 -07:00
Mark Thomas
3a1c10039e smartlog: compare dates not time when determining one week ago
Summary:
For the smartdate template function, when displaying commits in the last week
using the day name, we compare the exact times.  This means commits made late
in the day on one day, will still show using the day name early in the day the
following week.

Instead, compare just the dates.  We can simplify the other date-based
comparisons, too.

Reviewed By: farnz

Differential Revision: D8113953

fbshipit-source-id: b9bed59ccf349e7274ad65d7ed5a7e08c50d4b53
2018-05-23 09:02:50 -07:00
Jun Wu
af62797cf3 treestate: improve aggregated_state correctness and usability
Summary:
Previously, `aggregated_state` is only a union of bit flags. It makes
querying files with rare bits fast. But it cannot help with common bits.

This diff adds an `intersection` field, so both "having rare bits", and
"not having common bits" can be queried efficiently.

As we're here, use an explicit `None` to represent "need re-calculation",
instead of using `is_empty()`. This makes the code easier to reason about.
It also solves an issue in `add` that is caught by the next test.

Reviewed By: markbt

Differential Revision: D7886281

fbshipit-source-id: 4ce395883ea26ea9b33794e03c792ea157dc21d0
2018-05-23 06:12:46 -07:00
Jun Wu
acc362ae38 treestate: rename watchman_clock to metadata
Summary:
The field is a string that contains information `TreeState` itself does not
care about. It's up to the upper layer to decide how to use it, and it does
not have to be watchman clock, and might contain other fields like hostname,
ignore matcher hash, etc. So let's rename it to clarify.

Differential Revision: D7886282

fbshipit-source-id: 739a85d7a710918e0b18a9b7fe0e31b366bab447
2018-05-23 06:12:45 -07:00
Jun Wu
8d965905d1 treestate: add TreeState.path_complete and get_filtered_key
Summary: Similar to `TreeDirstate`, those methods are required.

Reviewed By: markbt

Differential Revision: D7874126

fbshipit-source-id: 6dbd6c47c7ba2ded7ea7389dfa9de4cf43db8a01
2018-05-23 06:12:45 -07:00
Jun Wu
b27143828b treestate: change Key from Vec<u8> to Box<[u8]>
Summary: This saves one `usize` per `Key`.

Differential Revision: D7861766

fbshipit-source-id: e44d6b98758966edd0f9823f2f50270ba5481b22
2018-05-23 06:12:45 -07:00
Jun Wu
395edeaea6 treestate: remove clear_filtered_keys
Summary:
The method looks like a foot-gun, and it's O(all entries) instead of
O(cached entries). Change `get_tracked_filtered_key` to take an identity of
the filter function explicitly to solve the problem.

Reviewed By: markbt

Differential Revision: D7861765

fbshipit-source-id: a57ca4a7597120a5b00c63f3f373a62e19e5a834
2018-05-23 06:12:45 -07:00
Jun Wu
e8a83ab74e treestate: use functions to filter out what to visit
Summary:
Follow up of the StateFlags change. Previously the code uses simple bitwise
operations to decide what to visit. That can not express complex conditions.
Let's use functions instead. Rustc should know how to inline those
functions.

Reviewed By: markbt

Differential Revision: D7860276

fbshipit-source-id: 71bf381e00adbb3259a1ae61dbd68fa67f02efdb
2018-05-23 06:12:45 -07:00
Jun Wu
ff2e0ccde1 treestate: add TreeState.visit
Summary: The visit function allows visiting files, filtered by StateFlags.

Reviewed By: markbt

Differential Revision: D7824117

fbshipit-source-id: 7625396cd942ca87056f322a7342979570853d37
2018-05-23 06:12:45 -07:00
Jun Wu
8ca928ced2 treestate: update aggregated_state inside Node.visit
Summary:
Node.visit might change internal file states. So aggregated_state might need
update.

Reviewed By: markbt

Differential Revision: D7824118

fbshipit-source-id: 4f935f427de4d1803524f5908466917e6163dd90
2018-05-23 06:12:45 -07:00
Jun Wu
ddc0a1bcfe treestate: use interior mutability for aggregated_state
Summary:
The upcoming diffs need to do something like:

  self.entries.as_mut().iter_mut() {
    self.aggregated_state = ...
  }

That cannot be done if accessing entries and aggregated_state both need
`&mut` borrow of `self`. So let's use interior mutability.

Reviewed By: markbt

Differential Revision: D7824116

fbshipit-source-id: 67dd317ebfbfc698e79ed6c0e96e69d3fe495a26
2018-05-23 06:12:45 -07:00
Jun Wu
225a0771b4 treestate: revise StateFlags bits
Summary:
The "added", "removed", "normal", "? (untracked)" 4 states could be simplified
to 2 bits: "EXIST_P1", "EXIST_NEXT". With "merge" considered, adding "EXIST_P2"
would be enough. This avoids some invalid states, making it easier to reason
about. It also makes Mercurial dirstate hacks like size = -1, size = -2 noting
"merge" and "otherparent" unnecessary.

With this change, the previous `state_required_all`, `state_required_any`
query parameters are not powerful enough. That would be changed to functions
in a later diff. There is a new need to select files by querying "unset" bits.
That will be addressed by D7886281.

Reviewed By: markbt

Differential Revision: D7860277

fbshipit-source-id: 15d198fbd0ffa858c8ed751d42dff73e06114c12
2018-05-23 06:12:45 -07:00
Jun Wu
0b3737c904 treestate: avoid broad borrow on self in Node.visit
Summary:
Looking at the `path` variable, it is now:

  vec![KeyRef<'a>, KeyRef<'a>, KeyRef<'a>, ...]

where `'a` is bounded to `self`. That's okay but makes it impossible to
modify `self` between `path.push` and the end of the `visit` function.

For `Node<FileStateV2>`, `self` needs to be modified, because `visitor`
might change `file`'s state, and `self.aggregated_state` needs to be updated
accordingly.

Basically, the elements of `Vec` should match the call stack, and have
different lifetimes. A nested `visit()` should have a nested lifetime on
`Vec` elements, instead of relying on borrowing `self`.

  vec![KeyRef<'a>, KeyRef<'b>, KeyRef<'c>, ...]
  #    visit(path) {
  #                let name: KeyRef<'b>; // instead of <'a>.
  #                path.push(name)
  #                visit(path) {
  #                            let name: KeyRef<'c>;
  #                            path.push(name)
  #                            visit(path) { ... }
  #                            }
  #                }

The previous diff introduces a `VecStack` struct to work in this case. Let's
use it. This also make sure all `path.pop()` happens automatically even if
panic happens.

Reviewed By: markbt

Differential Revision: D7797457

fbshipit-source-id: e1723fac3dbd7d244b69f1fc46d90bef64a29a3f
2018-05-23 06:12:45 -07:00
Jun Wu
7fa9772b67 treestate: add VecStack to support nested lifetimes matching stack frames
Summary:
The motivation is to have something like:

  // in Node.visit
  let mut vec = Vec::new();
  {
    vec.push(self.foobar()); // borrows self
    ...
    vec.pop(); // vec no longer contains "&self". But rustc won't know.
  }
  // want to mutate "self" here.

Reviewed By: markbt

Differential Revision: D7803738

fbshipit-source-id: 1bf2fc5788e7963f3144db490d044fcdb5193fad
2018-05-23 06:12:45 -07:00
Jun Wu
5cd280bf4e treestate: add TreeState.has_dir
Summary: This is needed for certain code paths. Fix `Tree.has_dir("/")` special case.

Differential Revision: D7797455

fbshipit-source-id: 5855e7ad6ef73eb07d590dd5201367b5c7f86a96
2018-05-23 06:12:45 -07:00
Jun Wu
6111ea14fd treestate: add basic tests for TreeState
Summary: Basic tests about serialization and add/remove/modify operations.

Differential Revision: D7769657

fbshipit-source-id: 767ee8fb1d813de5bc99a5d6c81978c89c51f298
2018-05-23 06:12:45 -07:00
Jun Wu
18317cc4b5 posix: improve error message about broken symlinks
Summary:
Improve `makedirs` error message so it would be more helpful when there are
broken symlinks.

Differential Revision: D8108794

fbshipit-source-id: 08013022642efde946ef9d5c6b06b4763f4ad68f
2018-05-23 06:12:45 -07:00
Jun Wu
ac486dcc7e templater: add "ifgt" function
Summary:
This will be used by the next change testing whether `{files|count}` is
exceeding a threshold for deciding which commit template to use.

Reviewed By: phillco

Differential Revision: D8101518

fbshipit-source-id: 51e918c6d8ab7d6e8b71708d9291945b2a09a632
2018-05-22 19:51:52 -07:00
Jun Wu
d76a7f6039 committemplate: show diff stats
Summary:
D5521665 added a `{stat}` template that can be used to show lines changes.
That gives more information than a plain template with just filenames, and
could serve as a hint about whether to split a diff or not.

Reviewed By: farnz

Differential Revision: D7960550

fbshipit-source-id: 5cb151b5d7ff72ce6260a7a76f15d7c17bd3bbd4
2018-05-22 19:51:52 -07:00
Shish Girling
1137cc5743 display 'Landing' status in hg ssl output
Summary:
It's super-useful to know the difference between "Accepted (You need to go and click the land button)" and "Accepted (We're just waiting for the land system to do its thing, no work for you right now)"

Alternative approach in D8074898

Reviewed By: mitrandir77

Differential Revision: D8074794

fbshipit-source-id: fdfda64e3a542518b8609e3a415d8cb3156373cf
2018-05-22 02:51:56 -07:00
Durham Goode
1733eb026c hgsql: refactor sql revision writing
Summary:
Let's move the sql revisions table writing to a function. In a future
diff we'll reuse this functionality to allow backfilling a database from an
existing repository.

Reviewed By: singhsrb

Differential Revision: D8066524

fbshipit-source-id: 173161d476eab6e35ccd0649494fd8f0f8b3093f
2018-05-21 11:38:52 -07:00
Durham Goode
1ce89cff9a hgsql: add sqltreestrip
Summary:
Adds a command for deleting trees from history, both in mysql and
locally. This will be useful for recovering from treemanifest corruption.

Reviewed By: singhsrb

Differential Revision: D8066231

fbshipit-source-id: 34a57572c526d99c62d7d4a9e48d60d668065547
2018-05-21 11:38:52 -07:00
Michael Bolin
a5e1820702 Split out a new hgevents extension from fsmonitor.
Summary:
This splits out the logic in the `fsmonitor` extension that is responsible for
publishing `hg.filemerge` and `hg.update` state changes to Watchman into
its own extension, `hgevents`. This is because we want the behavior of
`hgevents` when Hg is running in Eden, but we do not want the remaining
behavior of `fsmonitor` when Hg is running in Eden, so splitting the logic
into separate extensions is the most straightforward way to achieve that.

To achieve the split, we move some more logic that is common to both
`fsmonitor` and `hgevents` out of `hgext/fsmonitor/__init__.py` and into
`hgext/extlib/watchmanclient/__init__.py`. Then we move these lines
out of `extsetup()` in `fsmonitor` to create `extsetup()` in `hgevents`:

```
    extensions.wrapfunction(merge, 'update', wrapupdate)
    extensions.wrapfunction(filemerge, '_xmerge', _xmerge)
```

We also have to pull all of the transitive dependencies for this logic
into `hgevents`.

Finally, we also have to define a `reposetup()` function in `hgevents`
that does a subset of what `reposetup()` does in `fsmonitor`. Specifically,
it ensures that a Watchman client is created for a `repo`, as appropriate,
so that it can be used to dispatch state changes to Watchman in
`state_filemerge` and `state_update`.

Note that the utility functions `createclientforrepo()` and
`getclientforrepo()` have been added to ensure that only one
Watchman client is created (and shared) when both `fsmonitor`
and `hgevents` are enabled.

Today, when an Hg repo is created in Eden, we set `extensions.fsmonitor=!`
in the `.hg/hgrc`:

diffusion/FBS/browse/master/fbcode/eden/hooks/hg/post-clone.py$69

Therefore, to get existing repos (both Eden and non-Eden) to pick up
the `hgevents` extension automatically, we add it to the list of
`[extensions]` in `common.rc`:

diffusion/FBS/browse/master/fbcode/scm/hg/fb/staticfiles/etc/mercurial/repo-specific/common.rc$53-60

as this is where `fsmonitor` is configured. We do not enable it in
`scm/hg/fb/staticfiles/etc/mercurial/facebook.rc` because
there is no reason to enable `hgevents` on Hg servers. Therefore, we
also decline to add `hgevents` to the set of `DEFAULT_EXTENSIONS` in
`scm/hg/mercurial/extensions.py`.

Reviewed By: quark-zju

Differential Revision: D8003628

fbshipit-source-id: 4f23881f8c25f4638f5475c292537b0352ae8d15
2018-05-21 09:30:28 -07:00
Durham Goode
e1ec59a2f4 treemanifest: add key validation to the cachestore
Summary:
We had a bug where the cache store had a value that didn't correspond
with it's key. Let's add the key to the value so we can ensure they are always
paired correctly.

Reviewed By: phillco

Differential Revision: D8065151

fbshipit-source-id: 01be3a3432d1b4f5e9a234b35b8315c37b1869c3
2018-05-21 09:05:12 -07:00
Liubov Dmitrieva
aa61690c9a watchman rust client for hg: add test for arrays of objects
Summary:
watchman rust client: add tests for arrays of objects

this contains a reproducer test for broken compact arrays in combination with untagged enums

Reviewed By: sunshowers

Differential Revision: D7877495

fbshipit-source-id: 7fc3c05f1590e708a7645f0f9adbfd545e8bae42
2018-05-21 04:30:34 -07:00
Liubov Dmitrieva
44af40467e watchman rust client for hg: hg client
Summary:
Implement fsmonitor interfaces used by Mercurial fsmonitor extension, namely:

 - query_dirs
 - query_files
 - state_enter
 - state_leave

Reviewed By: quark-zju

Differential Revision: D7876428

fbshipit-source-id: 45c7a23bd0da4dcedcc473d75ac75fbd006a599a
2018-05-21 04:30:33 -07:00
Liubov Dmitrieva
7800d0ec9f watchman rust client for hg: initial implementation
Summary:
watchman rust client for mercurial needs

* describe responses and request with strong typing
* supports bser and json protocols
* command line transport and unix socket transport
* socket discovery (env or query command line client)
* read timeouts

Reviewed By: wez

Differential Revision: D7764586

fbshipit-source-id: 1f5725f6ce615e3e6e30395d09b5b37e0c2229d4
2018-05-21 04:30:32 -07:00
Jun Wu
b9b8f69767 repair: workaround ftruncate returning 1
Summary:
wjb has seen some weird truncate issues, which is caused by `ftruncate (2)`
returning 1 while its manpage says it returns <= 0. The recent contbuilds
also failed due to this.

While we're waiting for the upstream fix [1], let's workaround it from the
userspace to unblock the contbuild.

[1]: https://www.spinics.net/lists/linux-btrfs/msg78417.html

Reviewed By: DurhamG

Differential Revision: D8064611

fbshipit-source-id: df6c44255de47efa25a4c2b713a159ecd61b7478
2018-05-18 17:16:30 -07:00
Phil Cohen
9cae1acbc6 fix module imports for metrics.py
Summary: Didn't realize it was possible to land with a failure.

Reviewed By: DurhamG

Differential Revision: D8065037

fbshipit-source-id: abc34efeb4898f2068e57691adb0ddec8a64eabd
2018-05-18 16:31:30 -07:00
Phil Cohen
46bb070f04 move fbmetrics to __init__.py
Summary: Ran into an ImportError with the old layout.

Reviewed By: quark-zju

Differential Revision: D8061476

fbshipit-source-id: 6fc0b0c3a426e49eb5a43d59e13c69efd19fd453
2018-05-18 13:31:06 -07:00