mirror of
https://github.com/ankitects/anki.git
synced 2025-12-14 15:20:58 -05:00
Switch Rust import style (#2330)
* Prepare to switch Rust import style * Run nightly format Closes #2320 * Clean up a few imports * Enable comment wrapping * Wrap comments
This commit is contained in:
parent
9d84f357b6
commit
ded805b504
311 changed files with 3410 additions and 2687 deletions
|
|
@ -1,8 +1,7 @@
|
||||||
# this is not supported on stable Rust, and is ignored by the Bazel rules; it is only
|
# These settings are not supported on stable Rust, and are ignored by the ninja
|
||||||
# useful for manual invocation with 'cargo +nightly fmt'
|
# build script - to use them you need to run 'cargo +nightly fmt'
|
||||||
imports_granularity = "Crate"
|
|
||||||
group_imports = "StdExternalCrate"
|
group_imports = "StdExternalCrate"
|
||||||
|
imports_granularity = "Item"
|
||||||
# wrap_comments = true
|
imports_layout = "Vertical"
|
||||||
# imports_granularity = "Item"
|
wrap_comments = true
|
||||||
# imports_layout = "Vertical"
|
ignore = ["ascii_percent_encoding"]
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use std::{error::Error, fs, io::Read};
|
use std::error::Error;
|
||||||
|
use std::fs;
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
use camino::Utf8Path;
|
use camino::Utf8Path;
|
||||||
use sha2::Digest;
|
use sha2::Digest;
|
||||||
|
|
@ -117,7 +119,8 @@ fn extract(archive_path: &str, output_folder: &str) -> Result<()> {
|
||||||
archive.extract(&output_tmp)?;
|
archive.extract(&output_tmp)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if the output folder contains a single folder (eg foo-1.2), move it up a level
|
// if the output folder contains a single folder (eg foo-1.2), move it up a
|
||||||
|
// level
|
||||||
let mut entries: Vec<_> = output_tmp.read_dir_utf8()?.take(2).collect();
|
let mut entries: Vec<_> = output_tmp.read_dir_utf8()?.take(2).collect();
|
||||||
let first_entry = entries.pop().unwrap()?;
|
let first_entry = entries.pop().unwrap()?;
|
||||||
if entries.is_empty() && first_entry.metadata()?.is_dir() {
|
if entries.is_empty() && first_entry.metadata()?.is_dir() {
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,27 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use ninja_gen::{
|
use ninja_gen::action::BuildAction;
|
||||||
action::BuildAction,
|
use ninja_gen::command::RunCommand;
|
||||||
command::RunCommand,
|
use ninja_gen::copy::CopyFile;
|
||||||
copy::{CopyFile, CopyFiles},
|
use ninja_gen::copy::CopyFiles;
|
||||||
glob, hashmap, inputs,
|
use ninja_gen::glob;
|
||||||
node::{CompileSass, EsbuildScript, TypescriptCheck},
|
use ninja_gen::hashmap;
|
||||||
python::{python_format, PythonTest},
|
use ninja_gen::inputs;
|
||||||
Build, Result, Utf8Path, Utf8PathBuf,
|
use ninja_gen::node::CompileSass;
|
||||||
};
|
use ninja_gen::node::EsbuildScript;
|
||||||
|
use ninja_gen::node::TypescriptCheck;
|
||||||
|
use ninja_gen::python::python_format;
|
||||||
|
use ninja_gen::python::PythonTest;
|
||||||
|
use ninja_gen::Build;
|
||||||
|
use ninja_gen::Result;
|
||||||
|
use ninja_gen::Utf8Path;
|
||||||
|
use ninja_gen::Utf8PathBuf;
|
||||||
|
|
||||||
use crate::{
|
use crate::anki_version;
|
||||||
anki_version,
|
use crate::python::BuildWheel;
|
||||||
python::BuildWheel,
|
use crate::web::copy_mathjax;
|
||||||
web::{copy_mathjax, eslint},
|
use crate::web::eslint;
|
||||||
};
|
|
||||||
|
|
||||||
pub fn build_and_check_aqt(build: &mut Build) -> Result<()> {
|
pub fn build_and_check_aqt(build: &mut Build) -> Result<()> {
|
||||||
build_forms(build)?;
|
build_forms(build)?;
|
||||||
|
|
@ -294,7 +300,8 @@ impl BuildAction for BuildThemedIcon<'_> {
|
||||||
|
|
||||||
fn files(&mut self, build: &mut impl ninja_gen::build::FilesHandle) {
|
fn files(&mut self, build: &mut impl ninja_gen::build::FilesHandle) {
|
||||||
let stem = self.src_icon.file_stem().unwrap();
|
let stem = self.src_icon.file_stem().unwrap();
|
||||||
// eg foo-light.svg, foo-dark.svg, foo-FG_SUBTLE-light.svg, foo-FG_SUBTLE-dark.svg
|
// eg foo-light.svg, foo-dark.svg, foo-FG_SUBTLE-light.svg,
|
||||||
|
// foo-FG_SUBTLE-dark.svg
|
||||||
let outputs: Vec<_> = self
|
let outputs: Vec<_> = self
|
||||||
.colors
|
.colors
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,25 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use ninja_gen::{
|
use ninja_gen::action::BuildAction;
|
||||||
action::BuildAction,
|
use ninja_gen::archives::download_and_extract;
|
||||||
archives::{download_and_extract, empty_manifest, with_exe, OnlineArchive},
|
use ninja_gen::archives::empty_manifest;
|
||||||
cargo::{CargoBuild, RustOutput},
|
use ninja_gen::archives::with_exe;
|
||||||
git::SyncSubmodule,
|
use ninja_gen::archives::OnlineArchive;
|
||||||
glob,
|
use ninja_gen::cargo::CargoBuild;
|
||||||
input::BuildInput,
|
use ninja_gen::cargo::RustOutput;
|
||||||
inputs,
|
use ninja_gen::git::SyncSubmodule;
|
||||||
python::PythonEnvironment,
|
use ninja_gen::glob;
|
||||||
Build, Result, Utf8Path,
|
use ninja_gen::input::BuildInput;
|
||||||
};
|
use ninja_gen::inputs;
|
||||||
|
use ninja_gen::python::PythonEnvironment;
|
||||||
|
use ninja_gen::Build;
|
||||||
|
use ninja_gen::Result;
|
||||||
|
use ninja_gen::Utf8Path;
|
||||||
|
|
||||||
use crate::{
|
use crate::anki_version;
|
||||||
anki_version,
|
use crate::platform::overriden_python_target_platform;
|
||||||
platform::{overriden_python_target_platform, overriden_rust_target_triple},
|
use crate::platform::overriden_rust_target_triple;
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
enum DistKind {
|
enum DistKind {
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,18 @@ mod web;
|
||||||
|
|
||||||
use aqt::build_and_check_aqt;
|
use aqt::build_and_check_aqt;
|
||||||
use bundle::build_bundle;
|
use bundle::build_bundle;
|
||||||
use ninja_gen::{Build, Result};
|
use ninja_gen::Build;
|
||||||
use pylib::{build_pylib, check_pylib};
|
use ninja_gen::Result;
|
||||||
use python::{check_copyright, check_python, setup_python, setup_venv};
|
use pylib::build_pylib;
|
||||||
use rust::{build_rust, check_rust};
|
use pylib::check_pylib;
|
||||||
use web::{build_and_check_web, check_sql};
|
use python::check_copyright;
|
||||||
|
use python::check_python;
|
||||||
|
use python::setup_python;
|
||||||
|
use python::setup_venv;
|
||||||
|
use rust::build_rust;
|
||||||
|
use rust::check_rust;
|
||||||
|
use web::build_and_check_web;
|
||||||
|
use web::check_sql;
|
||||||
|
|
||||||
use crate::proto::check_proto;
|
use crate::proto::check_proto;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,14 @@ use std::env;
|
||||||
|
|
||||||
use ninja_gen::archives::Platform;
|
use ninja_gen::archives::Platform;
|
||||||
|
|
||||||
/// Usually None to use the host architecture; can be overriden by setting MAC_X86
|
/// Usually None to use the host architecture; can be overriden by setting
|
||||||
/// to build for x86_64 on Apple Silicon
|
/// MAC_X86 to build for x86_64 on Apple Silicon
|
||||||
pub fn overriden_rust_target_triple() -> Option<&'static str> {
|
pub fn overriden_rust_target_triple() -> Option<&'static str> {
|
||||||
overriden_python_target_platform().map(|p| p.as_rust_triple())
|
overriden_python_target_platform().map(|p| p.as_rust_triple())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Usually None to use the host architecture; can be overriden by setting MAC_X86
|
/// Usually None to use the host architecture; can be overriden by setting
|
||||||
/// to build for x86_64 on Apple Silicon
|
/// MAC_X86 to build for x86_64 on Apple Silicon
|
||||||
pub fn overriden_python_target_platform() -> Option<Platform> {
|
pub fn overriden_python_target_platform() -> Option<Platform> {
|
||||||
if env::var("MAC_X86").is_ok() {
|
if env::var("MAC_X86").is_ok() {
|
||||||
Some(Platform::MacX64)
|
Some(Platform::MacX64)
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,15 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use ninja_gen::{
|
use ninja_gen::archives::download_and_extract;
|
||||||
archives::{download_and_extract, with_exe},
|
use ninja_gen::archives::with_exe;
|
||||||
glob, hashmap, inputs,
|
use ninja_gen::glob;
|
||||||
protobuf::{protoc_archive, ClangFormat},
|
use ninja_gen::hashmap;
|
||||||
Build, Result,
|
use ninja_gen::inputs;
|
||||||
};
|
use ninja_gen::protobuf::protoc_archive;
|
||||||
|
use ninja_gen::protobuf::ClangFormat;
|
||||||
|
use ninja_gen::Build;
|
||||||
|
use ninja_gen::Result;
|
||||||
|
|
||||||
pub fn download_protoc(build: &mut Build) -> Result<()> {
|
pub fn download_protoc(build: &mut Build) -> Result<()> {
|
||||||
download_and_extract(
|
download_and_extract(
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,21 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use ninja_gen::{
|
use ninja_gen::action::BuildAction;
|
||||||
action::BuildAction,
|
use ninja_gen::archives::Platform;
|
||||||
archives::Platform,
|
use ninja_gen::command::RunCommand;
|
||||||
command::RunCommand,
|
use ninja_gen::copy::LinkFile;
|
||||||
copy::LinkFile,
|
use ninja_gen::glob;
|
||||||
glob, hashmap, inputs,
|
use ninja_gen::hashmap;
|
||||||
python::{python_format, PythonTest},
|
use ninja_gen::inputs;
|
||||||
Build, Result,
|
use ninja_gen::python::python_format;
|
||||||
};
|
use ninja_gen::python::PythonTest;
|
||||||
|
use ninja_gen::Build;
|
||||||
|
use ninja_gen::Result;
|
||||||
|
|
||||||
use crate::{
|
use crate::platform::overriden_python_target_platform;
|
||||||
platform::overriden_python_target_platform,
|
use crate::python::BuildWheel;
|
||||||
python::{BuildWheel, GenPythonProto},
|
use crate::python::GenPythonProto;
|
||||||
};
|
|
||||||
|
|
||||||
pub fn build_pylib(build: &mut Build) -> Result<()> {
|
pub fn build_pylib(build: &mut Build) -> Result<()> {
|
||||||
// generated files
|
// generated files
|
||||||
|
|
|
||||||
|
|
@ -3,18 +3,24 @@
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
use ninja_gen::{
|
use ninja_gen::action::BuildAction;
|
||||||
action::BuildAction,
|
use ninja_gen::archives::download_and_extract;
|
||||||
archives::{download_and_extract, OnlineArchive, Platform},
|
use ninja_gen::archives::OnlineArchive;
|
||||||
build::FilesHandle,
|
use ninja_gen::archives::Platform;
|
||||||
command::RunCommand,
|
use ninja_gen::build::FilesHandle;
|
||||||
glob, hashmap,
|
use ninja_gen::command::RunCommand;
|
||||||
input::BuildInput,
|
use ninja_gen::glob;
|
||||||
inputs,
|
use ninja_gen::hashmap;
|
||||||
python::{python_format, PythonEnvironment, PythonLint, PythonTypecheck},
|
use ninja_gen::input::BuildInput;
|
||||||
rsync::RsyncFiles,
|
use ninja_gen::inputs;
|
||||||
Build, Result, Utf8Path,
|
use ninja_gen::python::python_format;
|
||||||
};
|
use ninja_gen::python::PythonEnvironment;
|
||||||
|
use ninja_gen::python::PythonLint;
|
||||||
|
use ninja_gen::python::PythonTypecheck;
|
||||||
|
use ninja_gen::rsync::RsyncFiles;
|
||||||
|
use ninja_gen::Build;
|
||||||
|
use ninja_gen::Result;
|
||||||
|
use ninja_gen::Utf8Path;
|
||||||
|
|
||||||
fn python_archive(platform: Platform) -> OnlineArchive {
|
fn python_archive(platform: Platform) -> OnlineArchive {
|
||||||
match platform {
|
match platform {
|
||||||
|
|
@ -252,8 +258,8 @@ pub fn check_python(build: &mut Build) -> Result<()> {
|
||||||
|
|
||||||
fn add_pylint(build: &mut Build) -> Result<()> {
|
fn add_pylint(build: &mut Build) -> Result<()> {
|
||||||
// pylint does not support PEP420 implicit namespaces split across import paths,
|
// pylint does not support PEP420 implicit namespaces split across import paths,
|
||||||
// so we need to merge our pylib sources and generated files before invoking it, and
|
// so we need to merge our pylib sources and generated files before invoking it,
|
||||||
// add a top-level __init__.py
|
// and add a top-level __init__.py
|
||||||
build.add(
|
build.add(
|
||||||
"pylint/anki",
|
"pylint/anki",
|
||||||
RsyncFiles {
|
RsyncFiles {
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,20 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use ninja_gen::{
|
use ninja_gen::cargo::CargoBuild;
|
||||||
cargo::{CargoBuild, CargoClippy, CargoFormat, CargoRun, CargoTest, RustOutput},
|
use ninja_gen::cargo::CargoClippy;
|
||||||
git::SyncSubmodule,
|
use ninja_gen::cargo::CargoFormat;
|
||||||
glob, inputs, Build, Result,
|
use ninja_gen::cargo::CargoRun;
|
||||||
};
|
use ninja_gen::cargo::CargoTest;
|
||||||
|
use ninja_gen::cargo::RustOutput;
|
||||||
|
use ninja_gen::git::SyncSubmodule;
|
||||||
|
use ninja_gen::glob;
|
||||||
|
use ninja_gen::inputs;
|
||||||
|
use ninja_gen::Build;
|
||||||
|
use ninja_gen::Result;
|
||||||
|
|
||||||
use crate::{platform::overriden_rust_target_triple, proto::download_protoc};
|
use crate::platform::overriden_rust_target_triple;
|
||||||
|
use crate::proto::download_protoc;
|
||||||
|
|
||||||
pub fn build_rust(build: &mut Build) -> Result<()> {
|
pub fn build_rust(build: &mut Build) -> Result<()> {
|
||||||
prepare_translations(build)?;
|
prepare_translations(build)?;
|
||||||
|
|
|
||||||
|
|
@ -2,19 +2,25 @@
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
// use super::*;
|
// use super::*;
|
||||||
use ninja_gen::{
|
use ninja_gen::action::BuildAction;
|
||||||
action::BuildAction,
|
use ninja_gen::command::RunCommand;
|
||||||
command::RunCommand,
|
use ninja_gen::glob;
|
||||||
glob, hashmap,
|
use ninja_gen::hashmap;
|
||||||
input::BuildInput,
|
use ninja_gen::input::BuildInput;
|
||||||
inputs,
|
use ninja_gen::inputs;
|
||||||
node::{
|
use ninja_gen::node::node_archive;
|
||||||
node_archive, CompileSass, DPrint, EsbuildScript, Eslint, GenTypescriptProto, JestTest,
|
use ninja_gen::node::CompileSass;
|
||||||
SqlFormat, SvelteCheck, TypescriptCheck,
|
use ninja_gen::node::DPrint;
|
||||||
},
|
use ninja_gen::node::EsbuildScript;
|
||||||
rsync::RsyncFiles,
|
use ninja_gen::node::Eslint;
|
||||||
Build, Result,
|
use ninja_gen::node::GenTypescriptProto;
|
||||||
};
|
use ninja_gen::node::JestTest;
|
||||||
|
use ninja_gen::node::SqlFormat;
|
||||||
|
use ninja_gen::node::SvelteCheck;
|
||||||
|
use ninja_gen::node::TypescriptCheck;
|
||||||
|
use ninja_gen::rsync::RsyncFiles;
|
||||||
|
use ninja_gen::Build;
|
||||||
|
use ninja_gen::Result;
|
||||||
|
|
||||||
pub fn build_and_check_web(build: &mut Build) -> Result<()> {
|
pub fn build_and_check_web(build: &mut Build) -> Result<()> {
|
||||||
setup_node(build)?;
|
setup_node(build)?;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use crate::{build::FilesHandle, Build, Result};
|
use crate::build::FilesHandle;
|
||||||
|
use crate::Build;
|
||||||
|
use crate::Result;
|
||||||
|
|
||||||
pub trait BuildAction {
|
pub trait BuildAction {
|
||||||
/// Command line to invoke for each build statement.
|
/// Command line to invoke for each build statement.
|
||||||
|
|
@ -10,8 +12,9 @@ pub trait BuildAction {
|
||||||
/// Declare the input files and variables, and output files.
|
/// Declare the input files and variables, and output files.
|
||||||
fn files(&mut self, build: &mut impl FilesHandle);
|
fn files(&mut self, build: &mut impl FilesHandle);
|
||||||
|
|
||||||
/// If true, this action will not trigger a rebuild of dependent targets if the output
|
/// If true, this action will not trigger a rebuild of dependent targets if
|
||||||
/// files are unchanged. This corresponds to Ninja's "restat" argument.
|
/// the output files are unchanged. This corresponds to Ninja's "restat"
|
||||||
|
/// argument.
|
||||||
fn check_output_timestamps(&self) -> bool {
|
fn check_output_timestamps(&self) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
@ -21,8 +24,8 @@ pub trait BuildAction {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called on first action invocation; can be used to inject other build actions
|
/// Called on first action invocation; can be used to inject other build
|
||||||
/// to perform initial setup.
|
/// actions to perform initial setup.
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn on_first_instance(&self, build: &mut Build) -> Result<()> {
|
fn on_first_instance(&self, build: &mut Build) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,20 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use std::{borrow::Cow, collections::HashMap};
|
use std::borrow::Cow;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use camino::{Utf8Path, Utf8PathBuf};
|
use camino::Utf8Path;
|
||||||
|
use camino::Utf8PathBuf;
|
||||||
|
|
||||||
use crate::{
|
use crate::action::BuildAction;
|
||||||
action::BuildAction,
|
use crate::cargo::CargoBuild;
|
||||||
cargo::{CargoBuild, RustOutput},
|
use crate::cargo::RustOutput;
|
||||||
glob,
|
use crate::glob;
|
||||||
input::BuildInput,
|
use crate::input::BuildInput;
|
||||||
inputs, Build, Result,
|
use crate::inputs;
|
||||||
};
|
use crate::Build;
|
||||||
|
use crate::Result;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct OnlineArchive {
|
pub struct OnlineArchive {
|
||||||
|
|
@ -98,12 +101,14 @@ impl BuildAction for DownloadArchive {
|
||||||
|
|
||||||
struct ExtractArchive<'a, I> {
|
struct ExtractArchive<'a, I> {
|
||||||
pub archive_path: BuildInput,
|
pub archive_path: BuildInput,
|
||||||
/// The folder that the archive should be extracted into, relative to $builddir/extracted.
|
/// The folder that the archive should be extracted into, relative to
|
||||||
/// If the archive contains a single top-level folder, its contents will be extracted into the
|
/// $builddir/extracted. If the archive contains a single top-level
|
||||||
/// provided folder, so that output like tool-1.2/ can be extracted into tool/.
|
/// folder, its contents will be extracted into the provided folder, so
|
||||||
|
/// that output like tool-1.2/ can be extracted into tool/.
|
||||||
pub extraction_folder_name: &'a str,
|
pub extraction_folder_name: &'a str,
|
||||||
/// Files contained inside the archive, relative to the archive root, and excluding the top-level
|
/// Files contained inside the archive, relative to the archive root, and
|
||||||
/// folder if it is the sole top-level entry. Any files you wish to use as part of subsequent rules
|
/// excluding the top-level folder if it is the sole top-level entry.
|
||||||
|
/// Any files you wish to use as part of subsequent rules
|
||||||
/// must be declared here.
|
/// must be declared here.
|
||||||
pub file_manifest: HashMap<&'static str, I>,
|
pub file_manifest: HashMap<&'static str, I>,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,18 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use std::{
|
use std::collections::HashMap;
|
||||||
collections::{HashMap, HashSet},
|
use std::collections::HashSet;
|
||||||
fmt::Write,
|
use std::fmt::Write;
|
||||||
};
|
|
||||||
|
|
||||||
use camino::Utf8PathBuf;
|
use camino::Utf8PathBuf;
|
||||||
|
|
||||||
use crate::{
|
use crate::action::BuildAction;
|
||||||
action::BuildAction,
|
use crate::archives::Platform;
|
||||||
archives::Platform,
|
use crate::configure::ConfigureBuild;
|
||||||
configure::ConfigureBuild,
|
use crate::input::space_separated;
|
||||||
input::{space_separated, BuildInput},
|
use crate::input::BuildInput;
|
||||||
Result,
|
use crate::Result;
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Build {
|
pub struct Build {
|
||||||
|
|
@ -64,8 +62,8 @@ impl Build {
|
||||||
self.pools.push((name, size));
|
self.pools.push((name, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate the provided closure only once, using `key` to determine uniqueness.
|
/// Evaluate the provided closure only once, using `key` to determine
|
||||||
/// This key should not match any build action name.
|
/// uniqueness. This key should not match any build action name.
|
||||||
pub fn once_only(
|
pub fn once_only(
|
||||||
&mut self,
|
&mut self,
|
||||||
key: &'static str,
|
key: &'static str,
|
||||||
|
|
@ -155,15 +153,16 @@ rule {action_name}
|
||||||
self.add_resolved_files_to_group(target_group, &additional_files.clone())
|
self.add_resolved_files_to_group(target_group, &additional_files.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Outputs from a given build statement group. An error if no files have been registered yet.
|
/// Outputs from a given build statement group. An error if no files have
|
||||||
|
/// been registered yet.
|
||||||
pub fn group_outputs(&self, group_name: &'static str) -> &[String] {
|
pub fn group_outputs(&self, group_name: &'static str) -> &[String] {
|
||||||
self.groups
|
self.groups
|
||||||
.get(group_name)
|
.get(group_name)
|
||||||
.unwrap_or_else(|| panic!("expected files in {group_name}"))
|
.unwrap_or_else(|| panic!("expected files in {group_name}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Single output from a given build statement group. An error if no files have been registered yet,
|
/// Single output from a given build statement group. An error if no files
|
||||||
/// or more than one file has been registered.
|
/// have been registered yet, or more than one file has been registered.
|
||||||
pub fn group_output(&self, group_name: &'static str) -> String {
|
pub fn group_output(&self, group_name: &'static str) -> String {
|
||||||
let outputs = self.group_outputs(group_name);
|
let outputs = self.group_outputs(group_name);
|
||||||
assert_eq!(outputs.len(), 1);
|
assert_eq!(outputs.len(), 1);
|
||||||
|
|
@ -201,8 +200,8 @@ fn split_groups(group: &str) -> Vec<&str> {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BuildStatement<'a> {
|
struct BuildStatement<'a> {
|
||||||
/// Cache of outputs by already-evaluated build rules, allowing later rules to more easily consume
|
/// Cache of outputs by already-evaluated build rules, allowing later rules
|
||||||
/// the outputs of previous rules.
|
/// to more easily consume the outputs of previous rules.
|
||||||
existing_outputs: &'a HashMap<String, Vec<String>>,
|
existing_outputs: &'a HashMap<String, Vec<String>>,
|
||||||
rule_name: &'static str,
|
rule_name: &'static str,
|
||||||
// implicit refers to files that are not automatically assigned to $in and $out by Ninja,
|
// implicit refers to files that are not automatically assigned to $in and $out by Ninja,
|
||||||
|
|
@ -260,8 +259,8 @@ impl BuildStatement<'_> {
|
||||||
stmt
|
stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a list of all output files, which `Build` will add to `existing_outputs`,
|
/// Returns a list of all output files, which `Build` will add to
|
||||||
/// and any subgroups.
|
/// `existing_outputs`, and any subgroups.
|
||||||
fn render_into(mut self, buf: &mut String) -> (Vec<String>, Vec<(String, Vec<String>)>) {
|
fn render_into(mut self, buf: &mut String) -> (Vec<String>, Vec<(String, Vec<String>)>) {
|
||||||
let action_name = self.rule_name;
|
let action_name = self.rule_name;
|
||||||
let inputs_str = to_ninja_target_string(&self.explicit_inputs, &self.implicit_inputs);
|
let inputs_str = to_ninja_target_string(&self.explicit_inputs, &self.implicit_inputs);
|
||||||
|
|
@ -344,8 +343,9 @@ pub trait FilesHandle {
|
||||||
/// created so the file list can be accessed in the command. By convention,
|
/// created so the file list can be accessed in the command. By convention,
|
||||||
/// this is often `out`.
|
/// this is often `out`.
|
||||||
/// - If subgroup is true, the files are also placed in a subgroup. Eg
|
/// - If subgroup is true, the files are also placed in a subgroup. Eg
|
||||||
/// if a rule `foo` exists and subgroup `bar` is provided, the files are accessible
|
/// if a rule `foo` exists and subgroup `bar` is provided, the files are
|
||||||
/// via `:foo:bar`. The variable name must not be empty, or called `out`.
|
/// accessible via `:foo:bar`. The variable name must not be empty, or
|
||||||
|
/// called `out`.
|
||||||
fn add_outputs_ext(
|
fn add_outputs_ext(
|
||||||
&mut self,
|
&mut self,
|
||||||
variable: impl Into<String>,
|
variable: impl Into<String>,
|
||||||
|
|
@ -357,8 +357,8 @@ pub trait FilesHandle {
|
||||||
fn add_output_stamp(&mut self, path: impl Into<String>);
|
fn add_output_stamp(&mut self, path: impl Into<String>);
|
||||||
/// Set an env var for the duration of the provided command(s).
|
/// Set an env var for the duration of the provided command(s).
|
||||||
/// Note this is defined once for the rule, so if the value should change
|
/// Note this is defined once for the rule, so if the value should change
|
||||||
/// for each command, `constant_value` should reference a `$variable` you have
|
/// for each command, `constant_value` should reference a `$variable` you
|
||||||
/// defined.
|
/// have defined.
|
||||||
fn add_env_var(&mut self, key: &str, constant_value: &str);
|
fn add_env_var(&mut self, key: &str, constant_value: &str);
|
||||||
|
|
||||||
fn release_build(&self) -> bool;
|
fn release_build(&self) -> bool;
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,16 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use camino::{Utf8Path, Utf8PathBuf};
|
use camino::Utf8Path;
|
||||||
|
use camino::Utf8PathBuf;
|
||||||
|
|
||||||
use crate::{
|
use crate::action::BuildAction;
|
||||||
action::BuildAction, archives::with_exe, build::FilesHandle, input::BuildInput, inputs, Build,
|
use crate::archives::with_exe;
|
||||||
Result,
|
use crate::build::FilesHandle;
|
||||||
};
|
use crate::input::BuildInput;
|
||||||
|
use crate::inputs;
|
||||||
|
use crate::Build;
|
||||||
|
use crate::Result;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub enum RustOutput<'a> {
|
pub enum RustOutput<'a> {
|
||||||
|
|
@ -191,8 +195,8 @@ impl BuildAction for CargoFormat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Use Cargo to download and build a Rust binary. If `binary_name` is `foo`, a `$foo` variable
|
/// Use Cargo to download and build a Rust binary. If `binary_name` is `foo`, a
|
||||||
/// will be defined with the path to the binary.
|
/// `$foo` variable will be defined with the path to the binary.
|
||||||
pub struct CargoInstall {
|
pub struct CargoInstall {
|
||||||
pub binary_name: &'static str,
|
pub binary_name: &'static str,
|
||||||
/// eg 'foo --version 1.3' or '--git git://...'
|
/// eg 'foo --version 1.3' or '--git git://...'
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,10 @@
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::action::BuildAction;
|
||||||
action::BuildAction,
|
use crate::input::space_separated;
|
||||||
input::{space_separated, BuildInput},
|
use crate::input::BuildInput;
|
||||||
inputs,
|
use crate::inputs;
|
||||||
};
|
|
||||||
|
|
||||||
pub struct RunCommand<'a> {
|
pub struct RunCommand<'a> {
|
||||||
// Will be automatically included as a dependency
|
// Will be automatically included as a dependency
|
||||||
|
|
@ -24,8 +23,9 @@ impl BuildAction for RunCommand<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn files(&mut self, build: &mut impl crate::build::FilesHandle) {
|
fn files(&mut self, build: &mut impl crate::build::FilesHandle) {
|
||||||
// Because we've defined a generic rule instead of making one for a specific use case,
|
// Because we've defined a generic rule instead of making one for a specific use
|
||||||
// we need to manually intepolate variables in the user-provided args.
|
// case, we need to manually intepolate variables in the user-provided
|
||||||
|
// args.
|
||||||
let mut args = self.args.to_string();
|
let mut args = self.args.to_string();
|
||||||
for (key, inputs) in &self.inputs {
|
for (key, inputs) in &self.inputs {
|
||||||
let files = build.expand_inputs(inputs);
|
let files = build.expand_inputs(inputs);
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use crate::{
|
use crate::action::BuildAction;
|
||||||
action::BuildAction,
|
use crate::build::FilesHandle;
|
||||||
build::FilesHandle,
|
use crate::cargo::CargoBuild;
|
||||||
cargo::{CargoBuild, RustOutput},
|
use crate::cargo::RustOutput;
|
||||||
glob, inputs, Build, Result,
|
use crate::glob;
|
||||||
};
|
use crate::inputs;
|
||||||
|
use crate::Build;
|
||||||
|
use crate::Result;
|
||||||
|
|
||||||
pub struct ConfigureBuild {}
|
pub struct ConfigureBuild {}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,16 @@
|
||||||
|
|
||||||
use camino::Utf8Path;
|
use camino::Utf8Path;
|
||||||
|
|
||||||
use crate::{action::BuildAction, input::BuildInput};
|
use crate::action::BuildAction;
|
||||||
|
use crate::input::BuildInput;
|
||||||
|
|
||||||
/// Copy the provided files into the specified destination folder.
|
/// Copy the provided files into the specified destination folder.
|
||||||
/// Directory structure is not preserved - eg foo/bar.js is copied
|
/// Directory structure is not preserved - eg foo/bar.js is copied
|
||||||
/// into out/$output_folder/bar.js.
|
/// into out/$output_folder/bar.js.
|
||||||
pub struct CopyFiles<'a> {
|
pub struct CopyFiles<'a> {
|
||||||
pub inputs: BuildInput,
|
pub inputs: BuildInput,
|
||||||
/// The folder (relative to the build folder) that files should be copied into.
|
/// The folder (relative to the build folder) that files should be copied
|
||||||
|
/// into.
|
||||||
pub output_folder: &'a str,
|
pub output_folder: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -51,8 +53,9 @@ impl BuildAction for CopyFile<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a symbolic link to the provided output path, which should be relative to
|
/// Create a symbolic link to the provided output path, which should be relative
|
||||||
/// the output folder. This can be used to create a copy with a different name.
|
/// to the output folder. This can be used to create a copy with a different
|
||||||
|
/// name.
|
||||||
pub struct LinkFile<'a> {
|
pub struct LinkFile<'a> {
|
||||||
pub input: BuildInput,
|
pub input: BuildInput,
|
||||||
pub output: &'a str,
|
pub output: &'a str,
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{action::BuildAction, input::BuildInput};
|
use crate::action::BuildAction;
|
||||||
|
use crate::input::BuildInput;
|
||||||
|
|
||||||
pub struct SyncSubmodule {
|
pub struct SyncSubmodule {
|
||||||
pub path: &'static str,
|
pub path: &'static str,
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use std::{
|
use std::collections::hash_map::DefaultHasher;
|
||||||
collections::hash_map::DefaultHasher,
|
use std::hash::Hash;
|
||||||
hash::{Hash, Hasher},
|
use std::hash::Hasher;
|
||||||
};
|
|
||||||
|
|
||||||
pub fn simple_hash(hashable: impl Hash) -> u64 {
|
pub fn simple_hash(hashable: impl Hash) -> u64 {
|
||||||
let mut hasher = DefaultHasher::new();
|
let mut hasher = DefaultHasher::new();
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use std::{collections::HashMap, fmt::Display};
|
use std::collections::HashMap;
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
use camino::Utf8PathBuf;
|
use camino::Utf8PathBuf;
|
||||||
|
|
||||||
|
|
@ -126,7 +127,8 @@ lazy_static::lazy_static! {
|
||||||
static ref CACHED_FILES: Vec<Utf8PathBuf> = cache_files();
|
static ref CACHED_FILES: Vec<Utf8PathBuf> = cache_files();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Walking the source tree once instead of for each glob yields ~4x speed improvements.
|
/// Walking the source tree once instead of for each glob yields ~4x speed
|
||||||
|
/// improvements.
|
||||||
fn cache_files() -> Vec<Utf8PathBuf> {
|
fn cache_files() -> Vec<Utf8PathBuf> {
|
||||||
walkdir::WalkDir::new(".")
|
walkdir::WalkDir::new(".")
|
||||||
// ensure the output order is predictable
|
// ensure the output order is predictable
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ pub mod rsync;
|
||||||
pub mod sass;
|
pub mod sass;
|
||||||
|
|
||||||
pub use build::Build;
|
pub use build::Build;
|
||||||
pub use camino::{Utf8Path, Utf8PathBuf};
|
pub use camino::Utf8Path;
|
||||||
|
pub use camino::Utf8PathBuf;
|
||||||
pub use maplit::hashmap;
|
pub use maplit::hashmap;
|
||||||
pub use which::which;
|
pub use which::which;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,17 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use std::{borrow::Cow, collections::HashMap};
|
use std::borrow::Cow;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::action::BuildAction;
|
||||||
action::BuildAction,
|
use crate::archives::download_and_extract;
|
||||||
archives::{download_and_extract, OnlineArchive, Platform},
|
use crate::archives::OnlineArchive;
|
||||||
hash::simple_hash,
|
use crate::archives::Platform;
|
||||||
input::{space_separated, BuildInput},
|
use crate::hash::simple_hash;
|
||||||
};
|
use crate::input::space_separated;
|
||||||
|
use crate::input::BuildInput;
|
||||||
|
|
||||||
pub fn node_archive(platform: Platform) -> OnlineArchive {
|
pub fn node_archive(platform: Platform) -> OnlineArchive {
|
||||||
match platform {
|
match platform {
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,14 @@
|
||||||
|
|
||||||
use maplit::hashmap;
|
use maplit::hashmap;
|
||||||
|
|
||||||
use crate::{
|
use crate::action::BuildAction;
|
||||||
action::BuildAction,
|
use crate::archives::download_and_extract;
|
||||||
archives::{download_and_extract, with_exe, OnlineArchive, Platform},
|
use crate::archives::with_exe;
|
||||||
hash::simple_hash,
|
use crate::archives::OnlineArchive;
|
||||||
input::BuildInput,
|
use crate::archives::Platform;
|
||||||
inputs,
|
use crate::hash::simple_hash;
|
||||||
};
|
use crate::input::BuildInput;
|
||||||
|
use crate::inputs;
|
||||||
|
|
||||||
pub fn protoc_archive(platform: Platform) -> OnlineArchive {
|
pub fn protoc_archive(platform: Platform) -> OnlineArchive {
|
||||||
match platform {
|
match platform {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,12 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use crate::{action::BuildAction, hash::simple_hash, input::BuildInput, inputs, Build, Result};
|
use crate::action::BuildAction;
|
||||||
|
use crate::hash::simple_hash;
|
||||||
|
use crate::input::BuildInput;
|
||||||
|
use crate::inputs;
|
||||||
|
use crate::Build;
|
||||||
|
use crate::Result;
|
||||||
|
|
||||||
pub struct PythonEnvironment<'a> {
|
pub struct PythonEnvironment<'a> {
|
||||||
pub folder: &'static str,
|
pub folder: &'static str,
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use std::{fmt::Write, fs::read_to_string};
|
use std::fmt::Write;
|
||||||
|
use std::fs::read_to_string;
|
||||||
|
|
||||||
use crate::{archives::with_exe, input::space_separated, Build};
|
use crate::archives::with_exe;
|
||||||
|
use crate::input::space_separated;
|
||||||
|
use crate::Build;
|
||||||
|
|
||||||
impl Build {
|
impl Build {
|
||||||
pub fn render(&self) -> String {
|
pub fn render(&self) -> String {
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,16 @@
|
||||||
|
|
||||||
use camino::Utf8Path;
|
use camino::Utf8Path;
|
||||||
|
|
||||||
use crate::{
|
use crate::action::BuildAction;
|
||||||
action::BuildAction,
|
use crate::build::FilesHandle;
|
||||||
build::FilesHandle,
|
use crate::input::space_separated;
|
||||||
input::{space_separated, BuildInput},
|
use crate::input::BuildInput;
|
||||||
};
|
|
||||||
|
|
||||||
/// Rsync the provided inputs into `output_folder`, preserving directory structure,
|
/// Rsync the provided inputs into `output_folder`, preserving directory
|
||||||
/// eg foo/bar.js -> out/$target_folder/foo/bar.js. `strip_prefix` can be used to
|
/// structure, eg foo/bar.js -> out/$target_folder/foo/bar.js. `strip_prefix`
|
||||||
/// remove a portion of the the path when copying. If the input files are from previous
|
/// can be used to remove a portion of the the path when copying. If the input
|
||||||
/// build outputs, the prefix should begin with `$builddir/`.
|
/// files are from previous build outputs, the prefix should begin with
|
||||||
|
/// `$builddir/`.
|
||||||
pub struct RsyncFiles<'a> {
|
pub struct RsyncFiles<'a> {
|
||||||
pub inputs: BuildInput,
|
pub inputs: BuildInput,
|
||||||
pub target_folder: &'a str,
|
pub target_folder: &'a str,
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use crate::{
|
use crate::action::BuildAction;
|
||||||
action::BuildAction,
|
use crate::cargo::CargoInstall;
|
||||||
cargo::CargoInstall,
|
use crate::input::space_separated;
|
||||||
input::{space_separated, BuildInput},
|
use crate::input::BuildInput;
|
||||||
inputs, Build, Result,
|
use crate::inputs;
|
||||||
};
|
use crate::Build;
|
||||||
|
use crate::Result;
|
||||||
|
|
||||||
pub struct CompileSassWithGrass {
|
pub struct CompileSassWithGrass {
|
||||||
pub input: BuildInput,
|
pub input: BuildInput,
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,19 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use std::{env, fs, io::Write, process::Command, time::Instant};
|
use std::env;
|
||||||
|
use std::fs;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::process::Command;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
use camino::Utf8Path;
|
use camino::Utf8Path;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
|
use termcolor::Color;
|
||||||
|
use termcolor::ColorChoice;
|
||||||
|
use termcolor::ColorSpec;
|
||||||
|
use termcolor::StandardStream;
|
||||||
|
use termcolor::WriteColor;
|
||||||
|
|
||||||
#[derive(Args)]
|
#[derive(Args)]
|
||||||
pub struct BuildArgs {
|
pub struct BuildArgs {
|
||||||
|
|
@ -39,7 +47,8 @@ pub fn run_build(args: BuildArgs) {
|
||||||
maybe_reconfigure_build(&build_file, &path);
|
maybe_reconfigure_build(&build_file, &path);
|
||||||
}
|
}
|
||||||
|
|
||||||
// automatically convert foo:bar references to foo_bar, as Ninja can not represent the former
|
// automatically convert foo:bar references to foo_bar, as Ninja can not
|
||||||
|
// represent the former
|
||||||
let ninja_args = args.args.into_iter().map(|a| a.replace(':', "_"));
|
let ninja_args = args.args.into_iter().map(|a| a.replace(':', "_"));
|
||||||
|
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
|
|
@ -66,9 +75,10 @@ pub fn run_build(args: BuildArgs) {
|
||||||
// run build
|
// run build
|
||||||
let mut status = command.status().expect("ninja not installed");
|
let mut status = command.status().expect("ninja not installed");
|
||||||
if !status.success() && Instant::now().duration_since(start_time).as_secs() < 3 {
|
if !status.success() && Instant::now().duration_since(start_time).as_secs() < 3 {
|
||||||
// if the build fails quickly, there's a reasonable chance that build.ninja references
|
// if the build fails quickly, there's a reasonable chance that build.ninja
|
||||||
// a file that has been renamed/deleted. We currently don't capture stderr, so we can't
|
// references a file that has been renamed/deleted. We currently don't
|
||||||
// confirm, but in case that's the case, we regenerate the build.ninja file then try again.
|
// capture stderr, so we can't confirm, but in case that's the case, we
|
||||||
|
// regenerate the build.ninja file then try again.
|
||||||
bootstrap_build();
|
bootstrap_build();
|
||||||
status = command.status().expect("ninja missing");
|
status = command.status().expect("ninja missing");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use std::{env, fs, process::Command};
|
use std::env;
|
||||||
|
use std::fs;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
use camino::Utf8PathBuf;
|
use camino::Utf8PathBuf;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
|
|
@ -15,8 +17,8 @@ pub struct BuildArtifactsArgs {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_artifacts(args: BuildArtifactsArgs) {
|
pub fn build_artifacts(args: BuildArtifactsArgs) {
|
||||||
// build.rs doesn't declare inputs from venv, so we need to force a rebuild to ensure
|
// build.rs doesn't declare inputs from venv, so we need to force a rebuild to
|
||||||
// changes to our libs/the venv get included
|
// ensure changes to our libs/the venv get included
|
||||||
let artifacts = args.bundle_root.join("artifacts");
|
let artifacts = args.bundle_root.join("artifacts");
|
||||||
if artifacts.exists() {
|
if artifacts.exists() {
|
||||||
fs::remove_dir_all(&artifacts).unwrap();
|
fs::remove_dir_all(&artifacts).unwrap();
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,18 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use std::{env, fs, process::Command};
|
use std::env;
|
||||||
|
use std::fs;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
use camino::{Utf8Path, Utf8PathBuf};
|
use camino::Utf8Path;
|
||||||
use clap::{Args, ValueEnum};
|
use camino::Utf8PathBuf;
|
||||||
|
use clap::Args;
|
||||||
|
use clap::ValueEnum;
|
||||||
|
|
||||||
use crate::{
|
use crate::paths::absolute_msys_path;
|
||||||
paths::{absolute_msys_path, unix_path},
|
use crate::paths::unix_path;
|
||||||
run::run_silent,
|
use crate::run::run_silent;
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, ValueEnum, Debug)]
|
#[derive(Clone, Copy, ValueEnum, Debug)]
|
||||||
enum DistKind {
|
enum DistKind {
|
||||||
|
|
@ -26,8 +29,8 @@ pub struct BuildDistFolderArgs {
|
||||||
pub fn build_dist_folder(args: BuildDistFolderArgs) {
|
pub fn build_dist_folder(args: BuildDistFolderArgs) {
|
||||||
let BuildDistFolderArgs { kind, folder_root } = args;
|
let BuildDistFolderArgs { kind, folder_root } = args;
|
||||||
fs::create_dir_all(&folder_root).unwrap();
|
fs::create_dir_all(&folder_root).unwrap();
|
||||||
// Start with Qt, as it's the largest, and we use --delete to ensure there are no
|
// Start with Qt, as it's the largest, and we use --delete to ensure there are
|
||||||
// stale files in lib/. Skipped on macOS as Qt is handled later.
|
// no stale files in lib/. Skipped on macOS as Qt is handled later.
|
||||||
if !cfg!(target_os = "macos") {
|
if !cfg!(target_os = "macos") {
|
||||||
copy_qt_from_venv(kind, &folder_root);
|
copy_qt_from_venv(kind, &folder_root);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,18 +15,23 @@ mod yarn;
|
||||||
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
use build::{run_build, BuildArgs};
|
use build::run_build;
|
||||||
use bundle::{
|
use build::BuildArgs;
|
||||||
artifacts::{build_artifacts, BuildArtifactsArgs},
|
use bundle::artifacts::build_artifacts;
|
||||||
binary::build_bundle_binary,
|
use bundle::artifacts::BuildArtifactsArgs;
|
||||||
folder::{build_dist_folder, BuildDistFolderArgs},
|
use bundle::binary::build_bundle_binary;
|
||||||
};
|
use bundle::folder::build_dist_folder;
|
||||||
// use bundle::{build_bundle_binary, build_dist_folder, BuildDistFolderArgs};
|
use bundle::folder::BuildDistFolderArgs;
|
||||||
use clap::{Parser, Subcommand};
|
use clap::Parser;
|
||||||
use pyenv::{setup_pyenv, PyenvArgs};
|
use clap::Subcommand;
|
||||||
use rsync::{rsync_files, RsyncArgs};
|
use pyenv::setup_pyenv;
|
||||||
use run::{run_commands, RunArgs};
|
use pyenv::PyenvArgs;
|
||||||
use yarn::{setup_yarn, YarnArgs};
|
use rsync::rsync_files;
|
||||||
|
use rsync::RsyncArgs;
|
||||||
|
use run::run_commands;
|
||||||
|
use run::RunArgs;
|
||||||
|
use yarn::setup_yarn;
|
||||||
|
use yarn::YarnArgs;
|
||||||
|
|
||||||
pub type Result<T, E = Box<dyn Error>> = std::result::Result<T, E>;
|
pub type Result<T, E = Box<dyn Error>> = std::result::Result<T, E>;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@
|
||||||
|
|
||||||
use camino::Utf8Path;
|
use camino::Utf8Path;
|
||||||
|
|
||||||
/// On Unix, just a normal path. On Windows, c:\foo\bar.txt becomes /c/foo/bar.txt,
|
/// On Unix, just a normal path. On Windows, c:\foo\bar.txt becomes
|
||||||
/// which msys rsync expects.
|
/// /c/foo/bar.txt, which msys rsync expects.
|
||||||
pub fn absolute_msys_path(path: &Utf8Path) -> String {
|
pub fn absolute_msys_path(path: &Utf8Path) -> String {
|
||||||
let path = path.canonicalize_utf8().unwrap().into_string();
|
let path = path.canonicalize_utf8().unwrap().into_string();
|
||||||
if !cfg!(windows) {
|
if !cfg!(windows) {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ pub struct PyenvArgs {
|
||||||
venv_args: Vec<String>,
|
venv_args: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set up a venv if one doesn't already exist, and then sync packages with provided requirements file.
|
/// Set up a venv if one doesn't already exist, and then sync packages with
|
||||||
|
/// provided requirements file.
|
||||||
pub fn setup_pyenv(args: PyenvArgs) {
|
pub fn setup_pyenv(args: PyenvArgs) {
|
||||||
let pyenv_folder = Utf8Path::new(&args.pyenv_folder);
|
let pyenv_folder = Utf8Path::new(&args.pyenv_folder);
|
||||||
|
|
||||||
|
|
@ -35,8 +36,8 @@ pub fn setup_pyenv(args: PyenvArgs) {
|
||||||
);
|
);
|
||||||
|
|
||||||
if cfg!(windows) {
|
if cfg!(windows) {
|
||||||
// the first install on Windows throws an error the first time pip is upgraded, so we install
|
// the first install on Windows throws an error the first time pip is upgraded,
|
||||||
// it twice and swallow the first error
|
// so we install it twice and swallow the first error
|
||||||
let _output = Command::new(&pyenv_python)
|
let _output = Command::new(&pyenv_python)
|
||||||
.args(["-m", "pip", "install", "-r", &args.initial_reqs])
|
.args(["-m", "pip", "install", "-r", &args.initial_reqs])
|
||||||
.output()
|
.output()
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,8 @@ use std::process::Command;
|
||||||
use camino::Utf8Path;
|
use camino::Utf8Path;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
|
|
||||||
use crate::{paths::absolute_msys_path, run::run_silent};
|
use crate::paths::absolute_msys_path;
|
||||||
|
use crate::run::run_silent;
|
||||||
|
|
||||||
#[derive(Args)]
|
#[derive(Args)]
|
||||||
pub struct RsyncArgs {
|
pub struct RsyncArgs {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use std::{
|
use std::io::ErrorKind;
|
||||||
io::ErrorKind,
|
use std::process::Command;
|
||||||
process::{Command, Output},
|
use std::process::Output;
|
||||||
};
|
|
||||||
|
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use std::{path::Path, process::Command};
|
use std::path::Path;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
|
|
||||||
|
|
@ -21,8 +22,8 @@ pub fn setup_yarn(args: YarnArgs) {
|
||||||
std::fs::write(args.stamp, b"").unwrap();
|
std::fs::write(args.stamp, b"").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unfortunately a lot of the node ecosystem expects the output folder to reside
|
/// Unfortunately a lot of the node ecosystem expects the output folder to
|
||||||
/// in the repo root, so we need to link in our output folder.
|
/// reside in the repo root, so we need to link in our output folder.
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
fn link_node_modules() {
|
fn link_node_modules() {
|
||||||
let target = Path::new("node_modules");
|
let target = Path::new("node_modules");
|
||||||
|
|
@ -35,9 +36,10 @@ fn link_node_modules() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Things are more complicated on Windows - having $root/node_modules point to $root/out/node_modules
|
/// Things are more complicated on Windows - having $root/node_modules point to
|
||||||
/// breaks our globs for some reason, so we create the junction in the opposite direction instead.
|
/// $root/out/node_modules breaks our globs for some reason, so we create the
|
||||||
/// Ninja will have already created some empty folders based on our declared outputs, so we move the
|
/// junction in the opposite direction instead. Ninja will have already created
|
||||||
|
/// some empty folders based on our declared outputs, so we move the
|
||||||
/// created folder into the root.
|
/// created folder into the root.
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
fn link_node_modules() {
|
fn link_node_modules() {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
use camino::Utf8Path;
|
use camino::Utf8Path;
|
||||||
use snafu::{prelude::*, Whatever};
|
use snafu::prelude::*;
|
||||||
|
use snafu::Whatever;
|
||||||
|
|
||||||
type Result<T> = std::result::Result<T, Whatever>;
|
type Result<T> = std::result::Result<T, Whatever>;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,15 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use anki::{
|
use anki::backend::init_backend;
|
||||||
backend::{init_backend, Backend as RustBackend},
|
use anki::backend::Backend as RustBackend;
|
||||||
log::set_global_logger,
|
use anki::log::set_global_logger;
|
||||||
sync::http_server::SimpleServer,
|
use anki::sync::http_server::SimpleServer;
|
||||||
};
|
use pyo3::create_exception;
|
||||||
use pyo3::{
|
use pyo3::exceptions::PyException;
|
||||||
create_exception, exceptions::PyException, prelude::*, types::PyBytes, wrap_pyfunction,
|
use pyo3::prelude::*;
|
||||||
};
|
use pyo3::types::PyBytes;
|
||||||
|
use pyo3::wrap_pyfunction;
|
||||||
|
|
||||||
#[pyclass(module = "_rsbridge")]
|
#[pyclass(module = "_rsbridge")]
|
||||||
struct Backend {
|
struct Backend {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,13 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use std::{env, process::Command};
|
use std::env;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::bail;
|
||||||
use camino::{Utf8Path, Utf8PathBuf};
|
use anyhow::Result;
|
||||||
|
use camino::Utf8Path;
|
||||||
|
use camino::Utf8PathBuf;
|
||||||
|
|
||||||
const CODESIGN_ARGS: &[&str] = &["-vvvv", "-o", "runtime", "-s", "Developer ID Application:"];
|
const CODESIGN_ARGS: &[&str] = &["-vvvv", "-o", "runtime", "-s", "Developer ID Application:"];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,13 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use std::{fs, process::Command};
|
use std::fs;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::Context;
|
||||||
use camino::{Utf8Path, Utf8PathBuf};
|
use anyhow::Result;
|
||||||
|
use camino::Utf8Path;
|
||||||
|
use camino::Utf8PathBuf;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
|
|
||||||
use crate::notarize::wait_then_staple_app;
|
use crate::notarize::wait_then_staple_app;
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,23 @@ mod codesign;
|
||||||
mod dmg;
|
mod dmg;
|
||||||
mod notarize;
|
mod notarize;
|
||||||
|
|
||||||
use std::{env, fs, os::unix::prelude::PermissionsExt, process::Command};
|
use std::env;
|
||||||
|
use std::fs;
|
||||||
|
use std::os::unix::prelude::PermissionsExt;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::bail;
|
||||||
|
use anyhow::Result;
|
||||||
use apple_bundles::MacOsApplicationBundleBuilder;
|
use apple_bundles::MacOsApplicationBundleBuilder;
|
||||||
use camino::{Utf8Path, Utf8PathBuf};
|
use camino::Utf8Path;
|
||||||
use clap::{Parser, Subcommand, ValueEnum};
|
use camino::Utf8PathBuf;
|
||||||
use codesign::{codesign_app, codesign_python_libs};
|
use clap::Parser;
|
||||||
use dmg::{make_dmgs, BuildDmgsArgs};
|
use clap::Subcommand;
|
||||||
|
use clap::ValueEnum;
|
||||||
|
use codesign::codesign_app;
|
||||||
|
use codesign::codesign_python_libs;
|
||||||
|
use dmg::make_dmgs;
|
||||||
|
use dmg::BuildDmgsArgs;
|
||||||
use notarize::notarize_app;
|
use notarize::notarize_app;
|
||||||
use plist::Value;
|
use plist::Value;
|
||||||
use simple_file_manifest::FileEntry;
|
use simple_file_manifest::FileEntry;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,13 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use std::{env, fs, process::Command};
|
use std::env;
|
||||||
|
use std::fs;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::bail;
|
||||||
|
use anyhow::Context;
|
||||||
|
use anyhow::Result;
|
||||||
use camino::Utf8Path;
|
use camino::Utf8Path;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,21 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use std::{fs, io::prelude::*, path::Path, process::Command};
|
use std::fs;
|
||||||
|
use std::io::prelude::*;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::bail;
|
||||||
use camino::{Utf8Path, Utf8PathBuf};
|
use anyhow::Context;
|
||||||
|
use anyhow::Result;
|
||||||
|
use camino::Utf8Path;
|
||||||
|
use camino::Utf8PathBuf;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use tugger_windows_codesign::{CodeSigningCertificate, SigntoolSign, SystemStore, TimestampServer};
|
use tugger_windows_codesign::CodeSigningCertificate;
|
||||||
|
use tugger_windows_codesign::SigntoolSign;
|
||||||
|
use tugger_windows_codesign::SystemStore;
|
||||||
|
use tugger_windows_codesign::TimestampServer;
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use anki::card_rendering::anki_tag_benchmark;
|
use anki::card_rendering::anki_tag_benchmark;
|
||||||
use criterion::{criterion_group, criterion_main, Criterion};
|
use criterion::criterion_group;
|
||||||
|
use criterion::criterion_main;
|
||||||
|
use criterion::Criterion;
|
||||||
|
|
||||||
pub fn criterion_benchmark(c: &mut Criterion) {
|
pub fn criterion_benchmark(c: &mut Criterion) {
|
||||||
c.bench_function("anki_tag_parse", |b| b.iter(|| anki_tag_benchmark()));
|
c.bench_function("anki_tag_parse", |b| b.iter(|| anki_tag_benchmark()));
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use std::{env, fmt::Write, path::PathBuf};
|
use std::env;
|
||||||
|
use std::fmt::Write;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
struct CustomGenerator {}
|
struct CustomGenerator {}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
//! Check the .ftl files at build time to ensure we don't get runtime load failures.
|
//! Check the .ftl files at build time to ensure we don't get runtime load
|
||||||
|
//! failures.
|
||||||
|
|
||||||
use fluent::{FluentBundle, FluentResource};
|
use fluent::FluentBundle;
|
||||||
|
use fluent::FluentResource;
|
||||||
use unic_langid::LanguageIdentifier;
|
use unic_langid::LanguageIdentifier;
|
||||||
|
|
||||||
use super::gather::TranslationsByLang;
|
use super::gather::TranslationsByLang;
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,15 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use std::{collections::HashSet, fmt::Write};
|
use std::collections::HashSet;
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
use fluent_syntax::{
|
use fluent_syntax::ast::Entry;
|
||||||
ast::{Entry, Expression, InlineExpression, Pattern, PatternElement},
|
use fluent_syntax::ast::Expression;
|
||||||
parser::parse,
|
use fluent_syntax::ast::InlineExpression;
|
||||||
};
|
use fluent_syntax::ast::Pattern;
|
||||||
|
use fluent_syntax::ast::PatternElement;
|
||||||
|
use fluent_syntax::parser::parse;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::gather::TranslationsByLang;
|
use crate::gather::TranslationsByLang;
|
||||||
|
|
@ -163,7 +166,8 @@ impl Visitor {
|
||||||
impl From<String> for Variable {
|
impl From<String> for Variable {
|
||||||
fn from(name: String) -> Self {
|
fn from(name: String) -> Self {
|
||||||
// rather than adding more items here as we add new strings, we should probably
|
// rather than adding more items here as we add new strings, we should probably
|
||||||
// try to either reuse existing ones, or consider some sort of Hungarian notation
|
// try to either reuse existing ones, or consider some sort of Hungarian
|
||||||
|
// notation
|
||||||
let kind = match name.as_str() {
|
let kind = match name.as_str() {
|
||||||
"cards" | "notes" | "count" | "amount" | "reviews" | "total" | "selected"
|
"cards" | "notes" | "count" | "amount" | "reviews" | "total" | "selected"
|
||||||
| "kilobytes" | "daysStart" | "daysEnd" | "days" | "secs-per-card" | "remaining"
|
| "kilobytes" | "daysStart" | "daysEnd" | "days" | "secs-per-card" | "remaining"
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
//! By default, the Qt translations will be included in rslib. EXTRA_FTL_ROOT can be set
|
//! By default, the Qt translations will be included in rslib. EXTRA_FTL_ROOT
|
||||||
//! to an external folder so the mobile clients can use their own translations instead.
|
//! can be set to an external folder so the mobile clients can use their own
|
||||||
|
//! translations instead.
|
||||||
|
|
||||||
use std::{
|
use std::collections::HashMap;
|
||||||
collections::HashMap,
|
use std::fs;
|
||||||
fs,
|
use std::path::Path;
|
||||||
path::{Path, PathBuf},
|
use std::path::PathBuf;
|
||||||
};
|
|
||||||
|
|
||||||
pub type TranslationsByFile = HashMap<String, String>;
|
pub type TranslationsByFile = HashMap<String, String>;
|
||||||
pub type TranslationsByLang = HashMap<String, TranslationsByFile>;
|
pub type TranslationsByLang = HashMap<String, TranslationsByFile>;
|
||||||
|
|
@ -26,7 +26,8 @@ pub fn get_ftl_data() -> TranslationsByLang {
|
||||||
if let Some(path) = extra_ftl_root() {
|
if let Some(path) = extra_ftl_root() {
|
||||||
// Mobile client has requested its own extra translations
|
// Mobile client has requested its own extra translations
|
||||||
add_translation_root(&mut map, &path, false);
|
add_translation_root(&mut map, &path, false);
|
||||||
// In a debug build, also include the Qt translations so that our Python unit tests pass.
|
// In a debug build, also include the Qt translations so that our Python unit
|
||||||
|
// tests pass.
|
||||||
if std::env::var("RELEASE").is_err() {
|
if std::env::var("RELEASE").is_err() {
|
||||||
add_folder(&mut map, &ftl_base.join("qt"), "templates");
|
add_folder(&mut map, &ftl_base.join("qt"), "templates");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,17 @@
|
||||||
|
|
||||||
//! Write strings to a strings.rs file that will be compiled into the binary.
|
//! Write strings to a strings.rs file that will be compiled into the binary.
|
||||||
|
|
||||||
use std::{fmt::Write, fs, path::PathBuf};
|
use std::fmt::Write;
|
||||||
|
use std::fs;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use inflections::Inflect;
|
use inflections::Inflect;
|
||||||
|
|
||||||
use crate::{
|
use crate::extract::Module;
|
||||||
extract::{Module, Translation, VariableKind},
|
use crate::extract::Translation;
|
||||||
gather::{TranslationsByFile, TranslationsByLang},
|
use crate::extract::VariableKind;
|
||||||
};
|
use crate::gather::TranslationsByFile;
|
||||||
|
use crate::gather::TranslationsByLang;
|
||||||
|
|
||||||
pub fn write_strings(map: &TranslationsByLang, modules: &[Module]) {
|
pub fn write_strings(map: &TranslationsByLang, modules: &[Module]) {
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,17 @@
|
||||||
|
|
||||||
mod generated;
|
mod generated;
|
||||||
|
|
||||||
use std::{
|
use std::borrow::Cow;
|
||||||
borrow::Cow,
|
use std::sync::Arc;
|
||||||
sync::{Arc, Mutex},
|
use std::sync::Mutex;
|
||||||
};
|
|
||||||
|
|
||||||
use fluent::{types::FluentNumber, FluentArgs, FluentResource, FluentValue};
|
use fluent::types::FluentNumber;
|
||||||
|
use fluent::FluentArgs;
|
||||||
|
use fluent::FluentResource;
|
||||||
|
use fluent::FluentValue;
|
||||||
use fluent_bundle::bundle::FluentBundle as FluentBundleOrig;
|
use fluent_bundle::bundle::FluentBundle as FluentBundleOrig;
|
||||||
use generated::{KEYS_BY_MODULE, STRINGS};
|
use generated::KEYS_BY_MODULE;
|
||||||
|
use generated::STRINGS;
|
||||||
use num_format::Locale;
|
use num_format::Locale;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use unic_langid::LanguageIdentifier;
|
use unic_langid::LanguageIdentifier;
|
||||||
|
|
@ -265,7 +268,8 @@ impl I18n {
|
||||||
key.to_string().into()
|
key.to_string().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return text from configured locales for use with the JS Fluent implementation.
|
/// Return text from configured locales for use with the JS Fluent
|
||||||
|
/// implementation.
|
||||||
pub fn resources_for_js(&self, desired_modules: &[String]) -> ResourcesForJavascript {
|
pub fn resources_for_js(&self, desired_modules: &[String]) -> ResourcesForJavascript {
|
||||||
let inner = self.inner.lock().unwrap();
|
let inner = self.inner.lock().unwrap();
|
||||||
let resources = get_modules(&inner.langs, desired_modules);
|
let resources = get_modules(&inner.langs, desired_modules);
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,24 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use std::{collections::HashSet, fs, io::BufReader, iter::FromIterator};
|
use std::collections::HashSet;
|
||||||
|
use std::fs;
|
||||||
|
use std::io::BufReader;
|
||||||
|
use std::iter::FromIterator;
|
||||||
|
|
||||||
use fluent_syntax::{ast, parser};
|
use fluent_syntax::ast;
|
||||||
|
use fluent_syntax::parser;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use walkdir::{DirEntry, WalkDir};
|
use walkdir::DirEntry;
|
||||||
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
use crate::serialize;
|
use crate::serialize;
|
||||||
|
|
||||||
/// Extract references from all Rust, Python, TS, Svelte, Swift and Designer files in
|
/// Extract references from all Rust, Python, TS, Svelte, Swift and Designer
|
||||||
/// the `roots`, convert them to kebab case and write them as a json to the
|
/// files in the `roots`, convert them to kebab case and write them as a json to
|
||||||
/// target file.
|
/// the target file.
|
||||||
pub fn extract_ftl_references<S1: AsRef<str>, S2: AsRef<str>>(roots: &[S1], target: S2) {
|
pub fn extract_ftl_references<S1: AsRef<str>, S2: AsRef<str>>(roots: &[S1], target: S2) {
|
||||||
let mut refs = HashSet::new();
|
let mut refs = HashSet::new();
|
||||||
for root in roots {
|
for root in roots {
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,12 @@
|
||||||
|
|
||||||
// copied from https://github.com/projectfluent/fluent-rs/pull/241
|
// copied from https://github.com/projectfluent/fluent-rs/pull/241
|
||||||
|
|
||||||
use std::fmt::{
|
use std::fmt;
|
||||||
Error, Write, {self},
|
use std::fmt::Error;
|
||||||
};
|
use std::fmt::Write;
|
||||||
|
|
||||||
use fluent_syntax::{ast::*, parser::Slice};
|
use fluent_syntax::ast::*;
|
||||||
|
use fluent_syntax::parser::Slice;
|
||||||
|
|
||||||
pub fn serialize<'s, S: Slice<'s>>(resource: &Resource<S>) -> String {
|
pub fn serialize<'s, S: Slice<'s>>(resource: &Resource<S>) -> String {
|
||||||
serialize_with_options(resource, Options::default())
|
serialize_with_options(resource, Options::default())
|
||||||
|
|
|
||||||
|
|
@ -5,20 +5,22 @@ use anki::links::HelpPage;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use std::{env, iter};
|
use std::env;
|
||||||
|
use std::iter;
|
||||||
|
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use linkcheck::{
|
use linkcheck::validation::check_web;
|
||||||
validation::{check_web, Context, Reason},
|
use linkcheck::validation::Context;
|
||||||
BasicContext,
|
use linkcheck::validation::Reason;
|
||||||
};
|
use linkcheck::BasicContext;
|
||||||
use reqwest::Url;
|
use reqwest::Url;
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Aggregates [`Outcome`]s by collecting the error messages of the invalid ones.
|
/// Aggregates [`Outcome`]s by collecting the error messages of the invalid
|
||||||
|
/// ones.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Outcomes(Vec<String>);
|
struct Outcomes(Vec<String>);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,9 @@ impl Collection {
|
||||||
///
|
///
|
||||||
/// - When 'default to the current deck' is enabled, we use the current deck
|
/// - When 'default to the current deck' is enabled, we use the current deck
|
||||||
/// if it's normal, the provided reviewer card's deck as a fallback, and
|
/// if it's normal, the provided reviewer card's deck as a fallback, and
|
||||||
/// Default as a final fallback. We then fetch the last used notetype stored
|
/// Default as a final fallback. We then fetch the last used notetype
|
||||||
/// in the deck, falling back to the global notetype, or the first available one.
|
/// stored in the deck, falling back to the global notetype, or the first
|
||||||
|
/// available one.
|
||||||
///
|
///
|
||||||
/// - Otherwise, each note type remembers the last deck cards were added to,
|
/// - Otherwise, each note type remembers the last deck cards were added to,
|
||||||
/// and we use that, defaulting to the current deck if missing, and
|
/// and we use that, defaulting to the current deck if missing, and
|
||||||
|
|
@ -49,7 +50,8 @@ impl Collection {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The currently selected deck, the home deck of the provided card, or the default deck.
|
/// The currently selected deck, the home deck of the provided card, or the
|
||||||
|
/// default deck.
|
||||||
fn get_current_deck_for_adding(
|
fn get_current_deck_for_adding(
|
||||||
&mut self,
|
&mut self,
|
||||||
home_deck_of_reviewer_card: DeckId,
|
home_deck_of_reviewer_card: DeckId,
|
||||||
|
|
@ -96,9 +98,10 @@ impl Collection {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the last deck added to with this notetype, provided it is valid.
|
/// Returns the last deck added to with this notetype, provided it is valid.
|
||||||
/// This is optional due to the inconsistent handling, where changes in notetype
|
/// This is optional due to the inconsistent handling, where changes in
|
||||||
/// may need to update the current deck, but not vice versa. If a previous deck is
|
/// notetype may need to update the current deck, but not vice versa. If
|
||||||
/// not set, we want to keep the current selection, instead of resetting it.
|
/// a previous deck is not set, we want to keep the current selection,
|
||||||
|
/// instead of resetting it.
|
||||||
pub(crate) fn default_deck_for_notetype(&mut self, ntid: NotetypeId) -> Result<Option<DeckId>> {
|
pub(crate) fn default_deck_for_notetype(&mut self, ntid: NotetypeId) -> Result<Option<DeckId>> {
|
||||||
if let Some(last_deck_id) = self.get_last_deck_added_to_for_notetype(ntid) {
|
if let Some(last_deck_id) = self.get_last_deck_added_to_for_notetype(ntid) {
|
||||||
if let Some(deck) = self.get_deck(last_deck_id)? {
|
if let Some(deck) = self.get_deck(last_deck_id)? {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use crate::{adding::DeckAndNotetype, pb::notes::DeckAndNotetype as DeckAndNotetypeProto};
|
use crate::adding::DeckAndNotetype;
|
||||||
|
use crate::pb::notes::DeckAndNotetype as DeckAndNotetypeProto;
|
||||||
|
|
||||||
impl From<DeckAndNotetype> for DeckAndNotetypeProto {
|
impl From<DeckAndNotetype> for DeckAndNotetypeProto {
|
||||||
fn from(s: DeckAndNotetype) -> Self {
|
fn from(s: DeckAndNotetype) -> Self {
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,27 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use std::{
|
use std::collections::HashMap;
|
||||||
collections::HashMap,
|
use std::mem::size_of;
|
||||||
mem::size_of,
|
use std::sync::atomic::AtomicI32;
|
||||||
sync::{
|
use std::sync::atomic::Ordering;
|
||||||
atomic::{AtomicI32, Ordering},
|
use std::sync::Mutex;
|
||||||
Mutex,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
use itertools::{
|
use itertools::FoldWhile;
|
||||||
FoldWhile,
|
use itertools::FoldWhile::Continue;
|
||||||
FoldWhile::{Continue, Done},
|
use itertools::FoldWhile::Done;
|
||||||
Itertools,
|
use itertools::Itertools;
|
||||||
};
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use rusqlite::ToSql;
|
use rusqlite::ToSql;
|
||||||
use serde_derive::Deserialize;
|
use serde_derive::Deserialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::collection::Collection;
|
||||||
collection::Collection,
|
use crate::error::Result;
|
||||||
error::Result,
|
use crate::pb::ankidroid::sql_value::Data;
|
||||||
pb::ankidroid::{sql_value::Data, DbResponse, DbResult, Row, SqlValue},
|
use crate::pb::ankidroid::DbResponse;
|
||||||
};
|
use crate::pb::ankidroid::DbResult;
|
||||||
|
use crate::pb::ankidroid::Row;
|
||||||
|
use crate::pb::ankidroid::SqlValue;
|
||||||
|
|
||||||
/// A pointer to the SqliteStorage object stored in a collection, used to
|
/// A pointer to the SqliteStorage object stored in a collection, used to
|
||||||
/// uniquely index results from multiple open collections at once.
|
/// uniquely index results from multiple open collections at once.
|
||||||
|
|
@ -76,9 +74,10 @@ impl Sizable for Row {
|
||||||
|
|
||||||
impl Sizable for DbResult {
|
impl Sizable for DbResult {
|
||||||
fn estimate_size(&self) -> usize {
|
fn estimate_size(&self) -> usize {
|
||||||
// Performance: It might be best to take the first x rows and determine the data types
|
// Performance: It might be best to take the first x rows and determine the data
|
||||||
// If we have floats or longs, they'll be a fixed size (excluding nulls) and should speed
|
// types If we have floats or longs, they'll be a fixed size (excluding
|
||||||
// up the calculation as we'll only calculate a subset of the columns.
|
// nulls) and should speed up the calculation as we'll only calculate a
|
||||||
|
// subset of the columns.
|
||||||
self.rows.iter().map(|x| x.estimate_size()).sum()
|
self.rows.iter().map(|x| x.estimate_size()).sum()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -96,8 +95,9 @@ fn select_slice_of_size<'a>(
|
||||||
let init: Vec<Row> = Vec::new();
|
let init: Vec<Row> = Vec::new();
|
||||||
rows.fold_while((0, init), |mut acc, x| {
|
rows.fold_while((0, init), |mut acc, x| {
|
||||||
let new_size = acc.0 + x.estimate_size();
|
let new_size = acc.0 + x.estimate_size();
|
||||||
// If the accumulator is 0, but we're over the size: return a single result so we don't loop forever.
|
// If the accumulator is 0, but we're over the size: return a single result so
|
||||||
// Theoretically, this shouldn't happen as data should be reasonably sized
|
// we don't loop forever. Theoretically, this shouldn't happen as data
|
||||||
|
// should be reasonably sized
|
||||||
if new_size > max_size && acc.0 > 0 {
|
if new_size > max_size && acc.0 > 0 {
|
||||||
Done(acc)
|
Done(acc)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -147,7 +147,8 @@ pub(crate) fn trim_and_cache_remaining(
|
||||||
) -> DbResponse {
|
) -> DbResponse {
|
||||||
let start_index = 0;
|
let start_index = 0;
|
||||||
|
|
||||||
// PERF: Could speed this up by not creating the vector and just calculating the count
|
// PERF: Could speed this up by not creating the vector and just calculating the
|
||||||
|
// count
|
||||||
let first_result = select_next_slice(values.rows.iter());
|
let first_result = select_next_slice(values.rows.iter());
|
||||||
|
|
||||||
let row_count = values.rows.len() as i32;
|
let row_count = values.rows.len() as i32;
|
||||||
|
|
@ -279,11 +280,12 @@ pub(crate) fn execute_for_row_count(col: &Collection, req: &[u8]) -> Result<i64>
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::backend::ankidroid::db::select_slice_of_size;
|
||||||
backend::ankidroid::db::{select_slice_of_size, Sizable},
|
use crate::backend::ankidroid::db::Sizable;
|
||||||
collection::open_test_collection,
|
use crate::collection::open_test_collection;
|
||||||
pb::ankidroid::{sql_value, Row, SqlValue},
|
use crate::pb::ankidroid::sql_value;
|
||||||
};
|
use crate::pb::ankidroid::Row;
|
||||||
|
use crate::pb::ankidroid::SqlValue;
|
||||||
|
|
||||||
fn gen_data() -> Vec<SqlValue> {
|
fn gen_data() -> Vec<SqlValue> {
|
||||||
vec![
|
vec![
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,17 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use crate::{
|
use crate::error::DbError;
|
||||||
error::{
|
use crate::error::DbErrorKind as DB;
|
||||||
DbError, DbErrorKind as DB, FilteredDeckError, InvalidInputError, NetworkError,
|
use crate::error::FilteredDeckError;
|
||||||
NetworkErrorKind as Net, NotFoundError, SearchErrorKind, SyncError, SyncErrorKind as Sync,
|
use crate::error::InvalidInputError;
|
||||||
},
|
use crate::error::NetworkError;
|
||||||
prelude::AnkiError,
|
use crate::error::NetworkErrorKind as Net;
|
||||||
};
|
use crate::error::NotFoundError;
|
||||||
|
use crate::error::SearchErrorKind;
|
||||||
|
use crate::error::SyncError;
|
||||||
|
use crate::error::SyncErrorKind as Sync;
|
||||||
|
use crate::prelude::AnkiError;
|
||||||
|
|
||||||
pub(super) fn debug_produce_error(s: &str) -> AnkiError {
|
pub(super) fn debug_produce_error(s: &str) -> AnkiError {
|
||||||
let info = "error_value".to_string();
|
let info = "error_value".to_string();
|
||||||
|
|
|
||||||
|
|
@ -4,23 +4,25 @@
|
||||||
pub(crate) mod db;
|
pub(crate) mod db;
|
||||||
pub(crate) mod error;
|
pub(crate) mod error;
|
||||||
|
|
||||||
use self::{db::active_sequences, error::debug_produce_error};
|
use self::db::active_sequences;
|
||||||
use super::{
|
use self::error::debug_produce_error;
|
||||||
dbproxy::{db_command_bytes, db_command_proto},
|
use super::dbproxy::db_command_bytes;
|
||||||
Backend,
|
use super::dbproxy::db_command_proto;
|
||||||
};
|
use super::Backend;
|
||||||
|
use crate::backend::ankidroid::db::execute_for_row_count;
|
||||||
|
use crate::backend::ankidroid::db::insert_for_id;
|
||||||
|
use crate::pb;
|
||||||
pub(super) use crate::pb::ankidroid::ankidroid_service::Service as AnkidroidService;
|
pub(super) use crate::pb::ankidroid::ankidroid_service::Service as AnkidroidService;
|
||||||
use crate::{
|
use crate::pb::ankidroid::DbResponse;
|
||||||
backend::ankidroid::db::{execute_for_row_count, insert_for_id},
|
use crate::pb::ankidroid::GetActiveSequenceNumbersResponse;
|
||||||
pb,
|
use crate::pb::ankidroid::GetNextResultPageRequest;
|
||||||
pb::{
|
use crate::pb::generic;
|
||||||
ankidroid::{DbResponse, GetActiveSequenceNumbersResponse, GetNextResultPageRequest},
|
use crate::pb::generic::Empty;
|
||||||
generic,
|
use crate::pb::generic::Int32;
|
||||||
generic::{Empty, Int32, Json},
|
use crate::pb::generic::Json;
|
||||||
},
|
use crate::prelude::*;
|
||||||
prelude::*,
|
use crate::scheduler::timing;
|
||||||
scheduler::{timing, timing::fixed_offset_from_minutes},
|
use crate::scheduler::timing::fixed_offset_from_minutes;
|
||||||
};
|
|
||||||
|
|
||||||
impl AnkidroidService for Backend {
|
impl AnkidroidService for Backend {
|
||||||
fn sched_timing_today_legacy(
|
fn sched_timing_today_legacy(
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,11 @@
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use super::Backend;
|
use super::Backend;
|
||||||
|
use crate::card::CardQueue;
|
||||||
|
use crate::card::CardType;
|
||||||
|
use crate::pb;
|
||||||
pub(super) use crate::pb::cards::cards_service::Service as CardsService;
|
pub(super) use crate::pb::cards::cards_service::Service as CardsService;
|
||||||
use crate::{
|
use crate::prelude::*;
|
||||||
card::{CardQueue, CardType},
|
|
||||||
pb,
|
|
||||||
prelude::*,
|
|
||||||
};
|
|
||||||
|
|
||||||
impl CardsService for Backend {
|
impl CardsService for Backend {
|
||||||
fn get_card(&self, input: pb::cards::CardId) -> Result<pb::cards::Card> {
|
fn get_card(&self, input: pb::cards::CardId) -> Result<pb::cards::Card> {
|
||||||
|
|
|
||||||
|
|
@ -2,21 +2,24 @@
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use super::Backend;
|
use super::Backend;
|
||||||
|
use crate::card_rendering::extract_av_tags;
|
||||||
|
use crate::card_rendering::strip_av_tags;
|
||||||
|
use crate::latex::extract_latex;
|
||||||
|
use crate::latex::extract_latex_expanding_clozes;
|
||||||
|
use crate::latex::ExtractedLatex;
|
||||||
|
use crate::markdown::render_markdown;
|
||||||
|
use crate::notetype::CardTemplateSchema11;
|
||||||
|
use crate::notetype::RenderCardOutput;
|
||||||
|
use crate::pb;
|
||||||
pub(super) use crate::pb::card_rendering::cardrendering_service::Service as CardRenderingService;
|
pub(super) use crate::pb::card_rendering::cardrendering_service::Service as CardRenderingService;
|
||||||
use crate::{
|
use crate::prelude::*;
|
||||||
card_rendering::{extract_av_tags, strip_av_tags},
|
use crate::template::RenderedNode;
|
||||||
latex::{extract_latex, extract_latex_expanding_clozes, ExtractedLatex},
|
use crate::text::decode_iri_paths;
|
||||||
markdown::render_markdown,
|
use crate::text::encode_iri_paths;
|
||||||
notetype::{CardTemplateSchema11, RenderCardOutput},
|
use crate::text::sanitize_html_no_images;
|
||||||
pb,
|
use crate::text::strip_html;
|
||||||
prelude::*,
|
use crate::text::strip_html_preserving_media_filenames;
|
||||||
template::RenderedNode,
|
use crate::typeanswer::compare_answer;
|
||||||
text::{
|
|
||||||
decode_iri_paths, encode_iri_paths, sanitize_html_no_images, strip_html,
|
|
||||||
strip_html_preserving_media_filenames,
|
|
||||||
},
|
|
||||||
typeanswer::compare_answer,
|
|
||||||
};
|
|
||||||
|
|
||||||
impl CardRenderingService for Backend {
|
impl CardRenderingService for Backend {
|
||||||
fn extract_av_tags(
|
fn extract_av_tags(
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,14 @@ use std::sync::MutexGuard;
|
||||||
|
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
|
||||||
use super::{progress::Progress, Backend};
|
use super::progress::Progress;
|
||||||
|
use super::Backend;
|
||||||
|
use crate::backend::progress::progress_to_proto;
|
||||||
|
use crate::collection::CollectionBuilder;
|
||||||
|
use crate::pb;
|
||||||
pub(super) use crate::pb::collection::collection_service::Service as CollectionService;
|
pub(super) use crate::pb::collection::collection_service::Service as CollectionService;
|
||||||
use crate::{
|
use crate::prelude::*;
|
||||||
backend::progress::progress_to_proto, collection::CollectionBuilder, pb, prelude::*,
|
use crate::storage::SchemaVersion;
|
||||||
storage::SchemaVersion,
|
|
||||||
};
|
|
||||||
|
|
||||||
impl CollectionService for Backend {
|
impl CollectionService for Backend {
|
||||||
fn latest_progress(&self, _input: pb::generic::Empty) -> Result<pb::collection::Progress> {
|
fn latest_progress(&self, _input: pb::generic::Empty) -> Result<pb::collection::Progress> {
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,13 @@
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use super::Backend;
|
use super::Backend;
|
||||||
|
use crate::config::BoolKey;
|
||||||
|
use crate::config::StringKey;
|
||||||
|
use crate::pb;
|
||||||
|
use crate::pb::config::config_key::Bool as BoolKeyProto;
|
||||||
|
use crate::pb::config::config_key::String as StringKeyProto;
|
||||||
pub(super) use crate::pb::config::config_service::Service as ConfigService;
|
pub(super) use crate::pb::config::config_service::Service as ConfigService;
|
||||||
use crate::{
|
use crate::prelude::*;
|
||||||
config::{BoolKey, StringKey},
|
|
||||||
pb,
|
|
||||||
pb::config::config_key::{Bool as BoolKeyProto, String as StringKeyProto},
|
|
||||||
prelude::*,
|
|
||||||
};
|
|
||||||
|
|
||||||
impl From<BoolKeyProto> for BoolKey {
|
impl From<BoolKeyProto> for BoolKey {
|
||||||
fn from(k: BoolKeyProto) -> Self {
|
fn from(k: BoolKeyProto) -> Self {
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,24 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use rusqlite::{
|
use rusqlite::params_from_iter;
|
||||||
params_from_iter,
|
use rusqlite::types::FromSql;
|
||||||
types::{FromSql, FromSqlError, ToSql, ToSqlOutput, ValueRef},
|
use rusqlite::types::FromSqlError;
|
||||||
OptionalExtension,
|
use rusqlite::types::ToSql;
|
||||||
};
|
use rusqlite::types::ToSqlOutput;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use rusqlite::types::ValueRef;
|
||||||
|
use rusqlite::OptionalExtension;
|
||||||
|
use serde_derive::Deserialize;
|
||||||
|
use serde_derive::Serialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::pb;
|
||||||
pb,
|
use crate::pb::ankidroid::sql_value::Data;
|
||||||
pb::ankidroid::{
|
use crate::pb::ankidroid::DbResponse;
|
||||||
sql_value::Data, DbResponse, DbResult as ProtoDbResult, Row, SqlValue as pb_SqlValue,
|
use crate::pb::ankidroid::DbResult as ProtoDbResult;
|
||||||
},
|
use crate::pb::ankidroid::Row;
|
||||||
prelude::*,
|
use crate::pb::ankidroid::SqlValue as pb_SqlValue;
|
||||||
storage::SqliteStorage,
|
use crate::prelude::*;
|
||||||
};
|
use crate::storage::SqliteStorage;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
#[serde(tag = "kind", rename_all = "lowercase")]
|
#[serde(tag = "kind", rename_all = "lowercase")]
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,12 @@
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use super::Backend;
|
use super::Backend;
|
||||||
|
use crate::deckconfig::DeckConfSchema11;
|
||||||
|
use crate::deckconfig::DeckConfig;
|
||||||
|
use crate::deckconfig::UpdateDeckConfigsRequest;
|
||||||
|
use crate::pb;
|
||||||
pub(super) use crate::pb::deckconfig::deckconfig_service::Service as DeckConfigService;
|
pub(super) use crate::pb::deckconfig::deckconfig_service::Service as DeckConfigService;
|
||||||
use crate::{
|
use crate::prelude::*;
|
||||||
deckconfig::{DeckConfSchema11, DeckConfig, UpdateDeckConfigsRequest},
|
|
||||||
pb,
|
|
||||||
prelude::*,
|
|
||||||
};
|
|
||||||
|
|
||||||
impl DeckConfigService for Backend {
|
impl DeckConfigService for Backend {
|
||||||
fn add_or_update_deck_config_legacy(
|
fn add_or_update_deck_config_legacy(
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,12 @@
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
use super::Backend;
|
use super::Backend;
|
||||||
|
use crate::decks::DeckSchema11;
|
||||||
|
use crate::decks::FilteredSearchOrder;
|
||||||
|
use crate::pb;
|
||||||
pub(super) use crate::pb::decks::decks_service::Service as DecksService;
|
pub(super) use crate::pb::decks::decks_service::Service as DecksService;
|
||||||
use crate::{
|
use crate::prelude::*;
|
||||||
decks::{DeckSchema11, FilteredSearchOrder},
|
use crate::scheduler::filtered::FilteredDeckForUpdate;
|
||||||
pb,
|
|
||||||
prelude::*,
|
|
||||||
scheduler::filtered::FilteredDeckForUpdate,
|
|
||||||
};
|
|
||||||
|
|
||||||
impl DecksService for Backend {
|
impl DecksService for Backend {
|
||||||
fn new_deck(&self, _input: pb::generic::Empty) -> Result<pb::decks::Deck> {
|
fn new_deck(&self, _input: pb::generic::Empty) -> Result<pb::decks::Deck> {
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use crate::{
|
use crate::error::AnkiError;
|
||||||
error::{AnkiError, SyncErrorKind},
|
use crate::error::SyncErrorKind;
|
||||||
pb,
|
use crate::pb;
|
||||||
pb::backend::backend_error::Kind,
|
use crate::pb::backend::backend_error::Kind;
|
||||||
prelude::*,
|
use crate::prelude::*;
|
||||||
};
|
|
||||||
|
|
||||||
impl AnkiError {
|
impl AnkiError {
|
||||||
pub fn into_protobuf(self, tr: &I18n) -> pb::backend::BackendError {
|
pub fn into_protobuf(self, tr: &I18n) -> pb::backend::BackendError {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use crate::{pb, prelude::*};
|
use crate::pb;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
impl From<Vec<u8>> for pb::generic::Json {
|
impl From<Vec<u8>> for pb::generic::Json {
|
||||||
fn from(json: Vec<u8>) -> Self {
|
fn from(json: Vec<u8>) -> Self {
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,15 @@
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use fluent::{FluentArgs, FluentValue};
|
use fluent::FluentArgs;
|
||||||
|
use fluent::FluentValue;
|
||||||
|
|
||||||
use super::Backend;
|
use super::Backend;
|
||||||
|
use crate::pb;
|
||||||
pub(super) use crate::pb::i18n::i18n_service::Service as I18nService;
|
pub(super) use crate::pb::i18n::i18n_service::Service as I18nService;
|
||||||
use crate::{
|
use crate::prelude::*;
|
||||||
pb,
|
use crate::scheduler::timespan::answer_button_time;
|
||||||
prelude::*,
|
use crate::scheduler::timespan::time_span;
|
||||||
scheduler::timespan::{answer_button_time, time_span},
|
|
||||||
};
|
|
||||||
|
|
||||||
impl I18nService for Backend {
|
impl I18nService for Backend {
|
||||||
fn translate_string(
|
fn translate_string(
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,18 @@
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use super::{progress::Progress, Backend};
|
use super::progress::Progress;
|
||||||
|
use super::Backend;
|
||||||
|
use crate::import_export::package::import_colpkg;
|
||||||
|
use crate::import_export::ExportProgress;
|
||||||
|
use crate::import_export::ImportProgress;
|
||||||
|
use crate::import_export::NoteLog;
|
||||||
|
use crate::pb;
|
||||||
|
use crate::pb::import_export::export_limit;
|
||||||
pub(super) use crate::pb::import_export::importexport_service::Service as ImportExportService;
|
pub(super) use crate::pb::import_export::importexport_service::Service as ImportExportService;
|
||||||
use crate::{
|
use crate::pb::import_export::ExportLimit;
|
||||||
import_export::{package::import_colpkg, ExportProgress, ImportProgress, NoteLog},
|
use crate::prelude::*;
|
||||||
pb,
|
use crate::search::SearchNode;
|
||||||
pb::import_export::{export_limit, ExportLimit},
|
|
||||||
prelude::*,
|
|
||||||
search::SearchNode,
|
|
||||||
};
|
|
||||||
|
|
||||||
impl ImportExportService for Backend {
|
impl ImportExportService for Backend {
|
||||||
fn export_collection_package(
|
fn export_collection_package(
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,10 @@
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use super::Backend;
|
use super::Backend;
|
||||||
|
use crate::pb;
|
||||||
|
use crate::pb::links::help_page_link_request::HelpPage;
|
||||||
pub(super) use crate::pb::links::links_service::Service as LinksService;
|
pub(super) use crate::pb::links::links_service::Service as LinksService;
|
||||||
use crate::{pb, pb::links::help_page_link_request::HelpPage, prelude::*};
|
use crate::prelude::*;
|
||||||
|
|
||||||
impl LinksService for Backend {
|
impl LinksService for Backend {
|
||||||
fn help_page_link(&self, input: pb::links::HelpPageLinkRequest) -> Result<pb::generic::String> {
|
fn help_page_link(&self, input: pb::links::HelpPageLinkRequest) -> Result<pb::generic::String> {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use super::{progress::Progress, Backend};
|
use super::progress::Progress;
|
||||||
|
use super::Backend;
|
||||||
|
use crate::media::check::MediaChecker;
|
||||||
|
use crate::pb;
|
||||||
pub(super) use crate::pb::media::media_service::Service as MediaService;
|
pub(super) use crate::pb::media::media_service::Service as MediaService;
|
||||||
use crate::{media::check::MediaChecker, pb, prelude::*};
|
use crate::prelude::*;
|
||||||
|
|
||||||
impl MediaService for Backend {
|
impl MediaService for Backend {
|
||||||
// media
|
// media
|
||||||
|
|
|
||||||
|
|
@ -29,39 +29,41 @@ mod stats;
|
||||||
mod sync;
|
mod sync;
|
||||||
mod tags;
|
mod tags;
|
||||||
|
|
||||||
use std::{
|
use std::result;
|
||||||
result,
|
use std::sync::Arc;
|
||||||
sync::{Arc, Mutex},
|
use std::sync::Mutex;
|
||||||
thread::JoinHandle,
|
use std::thread::JoinHandle;
|
||||||
};
|
|
||||||
|
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use progress::AbortHandleSlot;
|
use progress::AbortHandleSlot;
|
||||||
use prost::Message;
|
use prost::Message;
|
||||||
use tokio::{runtime, runtime::Runtime};
|
use tokio::runtime;
|
||||||
|
use tokio::runtime::Runtime;
|
||||||
|
|
||||||
use self::{
|
use self::ankidroid::AnkidroidService;
|
||||||
ankidroid::AnkidroidService,
|
use self::card::CardsService;
|
||||||
card::CardsService,
|
use self::cardrendering::CardRenderingService;
|
||||||
cardrendering::CardRenderingService,
|
use self::collection::CollectionService;
|
||||||
collection::CollectionService,
|
use self::config::ConfigService;
|
||||||
config::ConfigService,
|
use self::deckconfig::DeckConfigService;
|
||||||
deckconfig::DeckConfigService,
|
use self::decks::DecksService;
|
||||||
decks::DecksService,
|
use self::i18n::I18nService;
|
||||||
i18n::I18nService,
|
use self::import_export::ImportExportService;
|
||||||
import_export::ImportExportService,
|
use self::links::LinksService;
|
||||||
links::LinksService,
|
use self::media::MediaService;
|
||||||
media::MediaService,
|
use self::notes::NotesService;
|
||||||
notes::NotesService,
|
use self::notetypes::NotetypesService;
|
||||||
notetypes::NotetypesService,
|
use self::progress::ProgressState;
|
||||||
progress::ProgressState,
|
use self::scheduler::SchedulerService;
|
||||||
scheduler::SchedulerService,
|
use self::search::SearchService;
|
||||||
search::SearchService,
|
use self::stats::StatsService;
|
||||||
stats::StatsService,
|
use self::sync::SyncService;
|
||||||
sync::{SyncService, SyncState},
|
use self::sync::SyncState;
|
||||||
tags::TagsService,
|
use self::tags::TagsService;
|
||||||
};
|
use crate::backend::dbproxy::db_command_bytes;
|
||||||
use crate::{backend::dbproxy::db_command_bytes, pb, pb::backend::ServiceIndex, prelude::*};
|
use crate::pb;
|
||||||
|
use crate::pb::backend::ServiceIndex;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub struct Backend {
|
pub struct Backend {
|
||||||
col: Arc<Mutex<Option<Collection>>>,
|
col: Arc<Mutex<Option<Collection>>>,
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,10 @@
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use super::Backend;
|
use super::Backend;
|
||||||
|
use crate::cloze::add_cloze_numbers_in_string;
|
||||||
|
use crate::pb;
|
||||||
pub(super) use crate::pb::notes::notes_service::Service as NotesService;
|
pub(super) use crate::pb::notes::notes_service::Service as NotesService;
|
||||||
use crate::{cloze::add_cloze_numbers_in_string, pb, prelude::*};
|
use crate::prelude::*;
|
||||||
|
|
||||||
impl NotesService for Backend {
|
impl NotesService for Backend {
|
||||||
fn new_note(&self, input: pb::notetypes::NotetypeId) -> Result<pb::notes::Note> {
|
fn new_note(&self, input: pb::notetypes::NotetypeId) -> Result<pb::notes::Note> {
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,15 @@
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use super::Backend;
|
use super::Backend;
|
||||||
|
use crate::config::get_aux_notetype_config_key;
|
||||||
|
use crate::notetype::all_stock_notetypes;
|
||||||
|
use crate::notetype::ChangeNotetypeInput;
|
||||||
|
use crate::notetype::Notetype;
|
||||||
|
use crate::notetype::NotetypeChangeInfo;
|
||||||
|
use crate::notetype::NotetypeSchema11;
|
||||||
|
use crate::pb;
|
||||||
pub(super) use crate::pb::notetypes::notetypes_service::Service as NotetypesService;
|
pub(super) use crate::pb::notetypes::notetypes_service::Service as NotetypesService;
|
||||||
use crate::{
|
use crate::prelude::*;
|
||||||
config::get_aux_notetype_config_key,
|
|
||||||
notetype::{
|
|
||||||
all_stock_notetypes, ChangeNotetypeInput, Notetype, NotetypeChangeInfo, NotetypeSchema11,
|
|
||||||
},
|
|
||||||
pb,
|
|
||||||
prelude::*,
|
|
||||||
};
|
|
||||||
|
|
||||||
impl NotetypesService for Backend {
|
impl NotetypesService for Backend {
|
||||||
fn add_notetype(
|
fn add_notetype(
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use crate::{
|
use crate::ops::OpChanges;
|
||||||
ops::OpChanges,
|
use crate::pb;
|
||||||
pb,
|
use crate::prelude::*;
|
||||||
prelude::*,
|
use crate::undo::UndoOutput;
|
||||||
undo::{UndoOutput, UndoStatus},
|
use crate::undo::UndoStatus;
|
||||||
};
|
|
||||||
|
|
||||||
impl From<OpChanges> for pb::collection::OpChanges {
|
impl From<OpChanges> for pb::collection::OpChanges {
|
||||||
fn from(c: OpChanges) -> Self {
|
fn from(c: OpChanges) -> Self {
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,21 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::Arc;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
use futures::future::AbortHandle;
|
use futures::future::AbortHandle;
|
||||||
|
|
||||||
use super::Backend;
|
use super::Backend;
|
||||||
use crate::{
|
use crate::dbcheck::DatabaseCheckProgress;
|
||||||
dbcheck::DatabaseCheckProgress,
|
use crate::i18n::I18n;
|
||||||
i18n::I18n,
|
use crate::import_export::ExportProgress;
|
||||||
import_export::{ExportProgress, ImportProgress},
|
use crate::import_export::ImportProgress;
|
||||||
pb,
|
use crate::pb;
|
||||||
sync::{
|
use crate::sync::collection::normal::NormalSyncProgress;
|
||||||
collection::{
|
use crate::sync::collection::progress::FullSyncProgress;
|
||||||
normal::NormalSyncProgress,
|
use crate::sync::collection::progress::SyncStage;
|
||||||
progress::{FullSyncProgress, SyncStage},
|
use crate::sync::media::progress::MediaSyncProgress;
|
||||||
},
|
|
||||||
media::progress::MediaSyncProgress,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub(super) struct ThrottlingProgressHandler {
|
pub(super) struct ThrottlingProgressHandler {
|
||||||
pub state: Arc<Mutex<ProgressState>>,
|
pub state: Arc<Mutex<ProgressState>>,
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,12 @@
|
||||||
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use crate::{
|
use crate::pb;
|
||||||
pb,
|
use crate::prelude::*;
|
||||||
prelude::*,
|
use crate::scheduler::answering::CardAnswer;
|
||||||
scheduler::{
|
use crate::scheduler::answering::Rating;
|
||||||
answering::{CardAnswer, Rating},
|
use crate::scheduler::queue::QueuedCard;
|
||||||
queue::{QueuedCard, QueuedCards},
|
use crate::scheduler::queue::QueuedCards;
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
impl From<pb::scheduler::CardAnswer> for CardAnswer {
|
impl From<pb::scheduler::CardAnswer> for CardAnswer {
|
||||||
fn from(mut answer: pb::scheduler::CardAnswer) -> Self {
|
fn from(mut answer: pb::scheduler::CardAnswer) -> Self {
|
||||||
|
|
|
||||||
|
|
@ -5,20 +5,17 @@ mod answering;
|
||||||
mod states;
|
mod states;
|
||||||
|
|
||||||
use super::Backend;
|
use super::Backend;
|
||||||
|
use crate::pb;
|
||||||
pub(super) use crate::pb::scheduler::scheduler_service::Service as SchedulerService;
|
pub(super) use crate::pb::scheduler::scheduler_service::Service as SchedulerService;
|
||||||
use crate::{
|
use crate::prelude::*;
|
||||||
pb,
|
use crate::scheduler::new::NewCardDueOrder;
|
||||||
prelude::*,
|
use crate::scheduler::states::CardState;
|
||||||
scheduler::{
|
use crate::scheduler::states::SchedulingStates;
|
||||||
new::NewCardDueOrder,
|
use crate::stats::studied_today;
|
||||||
states::{CardState, SchedulingStates},
|
|
||||||
},
|
|
||||||
stats::studied_today,
|
|
||||||
};
|
|
||||||
|
|
||||||
impl SchedulerService for Backend {
|
impl SchedulerService for Backend {
|
||||||
/// This behaves like _updateCutoff() in older code - it also unburies at the start of
|
/// This behaves like _updateCutoff() in older code - it also unburies at
|
||||||
/// a new day.
|
/// the start of a new day.
|
||||||
fn sched_timing_today(
|
fn sched_timing_today(
|
||||||
&self,
|
&self,
|
||||||
_input: pb::generic::Empty,
|
_input: pb::generic::Empty,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use crate::{pb, scheduler::states::FilteredState};
|
use crate::pb;
|
||||||
|
use crate::scheduler::states::FilteredState;
|
||||||
|
|
||||||
impl From<FilteredState> for pb::scheduler::scheduling_state::Filtered {
|
impl From<FilteredState> for pb::scheduler::scheduling_state::Filtered {
|
||||||
fn from(state: FilteredState) -> Self {
|
fn from(state: FilteredState) -> Self {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use crate::{pb, scheduler::states::LearnState};
|
use crate::pb;
|
||||||
|
use crate::scheduler::states::LearnState;
|
||||||
|
|
||||||
impl From<pb::scheduler::scheduling_state::Learning> for LearnState {
|
impl From<pb::scheduler::scheduling_state::Learning> for LearnState {
|
||||||
fn from(state: pb::scheduler::scheduling_state::Learning) -> Self {
|
fn from(state: pb::scheduler::scheduling_state::Learning) -> Self {
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,11 @@ mod relearning;
|
||||||
mod rescheduling;
|
mod rescheduling;
|
||||||
mod review;
|
mod review;
|
||||||
|
|
||||||
use crate::{
|
use crate::pb;
|
||||||
pb,
|
use crate::scheduler::states::CardState;
|
||||||
scheduler::states::{CardState, NewState, NormalState, SchedulingStates},
|
use crate::scheduler::states::NewState;
|
||||||
};
|
use crate::scheduler::states::NormalState;
|
||||||
|
use crate::scheduler::states::SchedulingStates;
|
||||||
|
|
||||||
impl From<SchedulingStates> for pb::scheduler::SchedulingStates {
|
impl From<SchedulingStates> for pb::scheduler::SchedulingStates {
|
||||||
fn from(choices: SchedulingStates) -> Self {
|
fn from(choices: SchedulingStates) -> Self {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use crate::{pb, scheduler::states::NewState};
|
use crate::pb;
|
||||||
|
use crate::scheduler::states::NewState;
|
||||||
|
|
||||||
impl From<pb::scheduler::scheduling_state::New> for NewState {
|
impl From<pb::scheduler::scheduling_state::New> for NewState {
|
||||||
fn from(state: pb::scheduler::scheduling_state::New) -> Self {
|
fn from(state: pb::scheduler::scheduling_state::New) -> Self {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use crate::{pb, scheduler::states::NormalState};
|
use crate::pb;
|
||||||
|
use crate::scheduler::states::NormalState;
|
||||||
|
|
||||||
impl From<NormalState> for pb::scheduler::scheduling_state::Normal {
|
impl From<NormalState> for pb::scheduler::scheduling_state::Normal {
|
||||||
fn from(state: NormalState) -> Self {
|
fn from(state: NormalState) -> Self {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use crate::{pb, scheduler::states::PreviewState};
|
use crate::pb;
|
||||||
|
use crate::scheduler::states::PreviewState;
|
||||||
|
|
||||||
impl From<pb::scheduler::scheduling_state::Preview> for PreviewState {
|
impl From<pb::scheduler::scheduling_state::Preview> for PreviewState {
|
||||||
fn from(state: pb::scheduler::scheduling_state::Preview) -> Self {
|
fn from(state: pb::scheduler::scheduling_state::Preview) -> Self {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use crate::{pb, scheduler::states::RelearnState};
|
use crate::pb;
|
||||||
|
use crate::scheduler::states::RelearnState;
|
||||||
|
|
||||||
impl From<pb::scheduler::scheduling_state::Relearning> for RelearnState {
|
impl From<pb::scheduler::scheduling_state::Relearning> for RelearnState {
|
||||||
fn from(state: pb::scheduler::scheduling_state::Relearning) -> Self {
|
fn from(state: pb::scheduler::scheduling_state::Relearning) -> Self {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use crate::{pb, scheduler::states::ReschedulingFilterState};
|
use crate::pb;
|
||||||
|
use crate::scheduler::states::ReschedulingFilterState;
|
||||||
|
|
||||||
impl From<pb::scheduler::scheduling_state::ReschedulingFilter> for ReschedulingFilterState {
|
impl From<pb::scheduler::scheduling_state::ReschedulingFilter> for ReschedulingFilterState {
|
||||||
fn from(state: pb::scheduler::scheduling_state::ReschedulingFilter) -> Self {
|
fn from(state: pb::scheduler::scheduling_state::ReschedulingFilter) -> Self {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use crate::{pb, scheduler::states::ReviewState};
|
use crate::pb;
|
||||||
|
use crate::scheduler::states::ReviewState;
|
||||||
|
|
||||||
impl From<pb::scheduler::scheduling_state::Review> for ReviewState {
|
impl From<pb::scheduler::scheduling_state::Review> for ReviewState {
|
||||||
fn from(state: pb::scheduler::scheduling_state::Review) -> Self {
|
fn from(state: pb::scheduler::scheduling_state::Review) -> Self {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@
|
||||||
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use crate::{browser_table, i18n::I18n, pb};
|
use crate::browser_table;
|
||||||
|
use crate::i18n::I18n;
|
||||||
|
use crate::pb;
|
||||||
|
|
||||||
impl browser_table::Column {
|
impl browser_table::Column {
|
||||||
pub fn to_pb_column(self, i18n: &I18n) -> pb::search::browser_columns::Column {
|
pub fn to_pb_column(self, i18n: &I18n) -> pb::search::browser_columns::Column {
|
||||||
|
|
|
||||||
|
|
@ -4,17 +4,20 @@
|
||||||
mod browser_table;
|
mod browser_table;
|
||||||
mod search_node;
|
mod search_node;
|
||||||
|
|
||||||
use std::{str::FromStr, sync::Arc};
|
use std::str::FromStr;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use super::{notes::to_note_ids, Backend};
|
use super::notes::to_note_ids;
|
||||||
|
use super::Backend;
|
||||||
|
use crate::browser_table::Column;
|
||||||
|
use crate::pb;
|
||||||
pub(super) use crate::pb::search::search_service::Service as SearchService;
|
pub(super) use crate::pb::search::search_service::Service as SearchService;
|
||||||
use crate::{
|
use crate::pb::search::sort_order::Value as SortOrderProto;
|
||||||
browser_table::Column,
|
use crate::prelude::*;
|
||||||
pb,
|
use crate::search::replace_search_node;
|
||||||
pb::search::sort_order::Value as SortOrderProto,
|
use crate::search::JoinSearches;
|
||||||
prelude::*,
|
use crate::search::Node;
|
||||||
search::{replace_search_node, JoinSearches, Node, SortMode},
|
use crate::search::SortMode;
|
||||||
};
|
|
||||||
|
|
||||||
impl SearchService for Backend {
|
impl SearchService for Backend {
|
||||||
fn build_search_string(&self, input: pb::search::SearchNode) -> Result<pb::generic::String> {
|
fn build_search_string(&self, input: pb::search::SearchNode) -> Result<pb::generic::String> {
|
||||||
|
|
|
||||||
|
|
@ -3,20 +3,26 @@
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use crate::{
|
use crate::pb;
|
||||||
pb,
|
use crate::prelude::*;
|
||||||
prelude::*,
|
use crate::search::parse_search;
|
||||||
search::{
|
use crate::search::Negated;
|
||||||
parse_search, Negated, Node, PropertyKind, RatingKind, SearchNode, StateKind, TemplateKind,
|
use crate::search::Node;
|
||||||
},
|
use crate::search::PropertyKind;
|
||||||
text::{escape_anki_wildcards, escape_anki_wildcards_for_search_node},
|
use crate::search::RatingKind;
|
||||||
};
|
use crate::search::SearchNode;
|
||||||
|
use crate::search::StateKind;
|
||||||
|
use crate::search::TemplateKind;
|
||||||
|
use crate::text::escape_anki_wildcards;
|
||||||
|
use crate::text::escape_anki_wildcards_for_search_node;
|
||||||
|
|
||||||
impl TryFrom<pb::search::SearchNode> for Node {
|
impl TryFrom<pb::search::SearchNode> for Node {
|
||||||
type Error = AnkiError;
|
type Error = AnkiError;
|
||||||
|
|
||||||
fn try_from(msg: pb::search::SearchNode) -> std::result::Result<Self, Self::Error> {
|
fn try_from(msg: pb::search::SearchNode) -> std::result::Result<Self, Self::Error> {
|
||||||
use pb::search::search_node::{group::Joiner, Filter, Flag};
|
use pb::search::search_node::group::Joiner;
|
||||||
|
use pb::search::search_node::Filter;
|
||||||
|
use pb::search::search_node::Flag;
|
||||||
Ok(if let Some(filter) = msg.filter {
|
Ok(if let Some(filter) = msg.filter {
|
||||||
match filter {
|
match filter {
|
||||||
Filter::Tag(s) => SearchNode::from_tag_name(&s).into(),
|
Filter::Tag(s) => SearchNode::from_tag_name(&s).into(),
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,10 @@
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use super::Backend;
|
use super::Backend;
|
||||||
|
use crate::pb;
|
||||||
pub(super) use crate::pb::stats::stats_service::Service as StatsService;
|
pub(super) use crate::pb::stats::stats_service::Service as StatsService;
|
||||||
use crate::{pb, prelude::*, revlog::RevlogReviewKind};
|
use crate::prelude::*;
|
||||||
|
use crate::revlog::RevlogReviewKind;
|
||||||
|
|
||||||
impl StatsService for Backend {
|
impl StatsService for Backend {
|
||||||
fn card_stats(&self, input: pb::cards::CardId) -> Result<pb::stats::CardStatsResponse> {
|
fn card_stats(&self, input: pb::cards::CardId) -> Result<pb::stats::CardStatsResponse> {
|
||||||
|
|
|
||||||
|
|
@ -3,27 +3,29 @@
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use futures::future::{AbortHandle, AbortRegistration, Abortable};
|
use futures::future::AbortHandle;
|
||||||
|
use futures::future::AbortRegistration;
|
||||||
|
use futures::future::Abortable;
|
||||||
use pb::sync::sync_status_response::Required;
|
use pb::sync::sync_status_response::Required;
|
||||||
use reqwest::Url;
|
use reqwest::Url;
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
|
|
||||||
use super::{progress::AbortHandleSlot, Backend};
|
use super::progress::AbortHandleSlot;
|
||||||
|
use super::Backend;
|
||||||
|
use crate::pb;
|
||||||
pub(super) use crate::pb::sync::sync_service::Service as SyncService;
|
pub(super) use crate::pb::sync::sync_service::Service as SyncService;
|
||||||
use crate::{
|
use crate::pb::sync::SyncStatusResponse;
|
||||||
pb,
|
use crate::prelude::*;
|
||||||
pb::sync::SyncStatusResponse,
|
use crate::sync::collection::normal::ClientSyncState;
|
||||||
prelude::*,
|
use crate::sync::collection::normal::NormalSyncProgress;
|
||||||
sync::{
|
use crate::sync::collection::normal::SyncActionRequired;
|
||||||
collection::{
|
use crate::sync::collection::normal::SyncOutput;
|
||||||
normal::{ClientSyncState, NormalSyncProgress, SyncActionRequired, SyncOutput},
|
use crate::sync::collection::progress::sync_abort;
|
||||||
progress::{sync_abort, FullSyncProgress},
|
use crate::sync::collection::progress::FullSyncProgress;
|
||||||
status::online_sync_status_check,
|
use crate::sync::collection::status::online_sync_status_check;
|
||||||
},
|
use crate::sync::http_client::HttpSyncClient;
|
||||||
http_client::HttpSyncClient,
|
use crate::sync::login::sync_login;
|
||||||
login::{sync_login, SyncAuth},
|
use crate::sync::login::SyncAuth;
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub(super) struct SyncState {
|
pub(super) struct SyncState {
|
||||||
|
|
@ -264,8 +266,9 @@ impl Backend {
|
||||||
let state = rt.block_on(online_sync_status_check(local, &mut client))?;
|
let state = rt.block_on(online_sync_status_check(local, &mut client))?;
|
||||||
{
|
{
|
||||||
let mut guard = self.state.lock().unwrap();
|
let mut guard = self.state.lock().unwrap();
|
||||||
// On startup, the sync status check will block on network access, and then automatic syncing begins,
|
// On startup, the sync status check will block on network access, and then
|
||||||
// taking hold of the mutex. By the time we reach here, our network status may be out of date,
|
// automatic syncing begins, taking hold of the mutex. By the time
|
||||||
|
// we reach here, our network status may be out of date,
|
||||||
// so we discard it if stale.
|
// so we discard it if stale.
|
||||||
if guard.sync.remote_sync_status.last_check < time_at_check_begin {
|
if guard.sync.remote_sync_status.last_check < time_at_check_begin {
|
||||||
guard.sync.remote_sync_status.last_check = time_at_check_begin;
|
guard.sync.remote_sync_status.last_check = time_at_check_begin;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use super::{notes::to_note_ids, Backend};
|
use super::notes::to_note_ids;
|
||||||
|
use super::Backend;
|
||||||
|
use crate::pb;
|
||||||
pub(super) use crate::pb::tags::tags_service::Service as TagsService;
|
pub(super) use crate::pb::tags::tags_service::Service as TagsService;
|
||||||
use crate::{pb, prelude::*};
|
use crate::prelude::*;
|
||||||
|
|
||||||
impl TagsService for Backend {
|
impl TagsService for Backend {
|
||||||
fn clear_unused_tags(
|
fn clear_unused_tags(
|
||||||
|
|
|
||||||
|
|
@ -4,18 +4,22 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use strum::{Display, EnumIter, EnumString, IntoEnumIterator};
|
use strum::Display;
|
||||||
|
use strum::EnumIter;
|
||||||
|
use strum::EnumString;
|
||||||
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
use crate::{
|
use crate::card::CardQueue;
|
||||||
card::{CardQueue, CardType},
|
use crate::card::CardType;
|
||||||
card_rendering::prettify_av_tags,
|
use crate::card_rendering::prettify_av_tags;
|
||||||
notetype::{CardTemplate, NotetypeKind},
|
use crate::notetype::CardTemplate;
|
||||||
pb,
|
use crate::notetype::NotetypeKind;
|
||||||
prelude::*,
|
use crate::pb;
|
||||||
scheduler::{timespan::time_span, timing::SchedTimingToday},
|
use crate::prelude::*;
|
||||||
template::RenderedNode,
|
use crate::scheduler::timespan::time_span;
|
||||||
text::html_to_text_line,
|
use crate::scheduler::timing::SchedTimingToday;
|
||||||
};
|
use crate::template::RenderedNode;
|
||||||
|
use crate::text::html_to_text_line;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Display, EnumIter, EnumString)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy, Display, EnumIter, EnumString)]
|
||||||
#[strum(serialize_all = "camelCase")]
|
#[strum(serialize_all = "camelCase")]
|
||||||
|
|
@ -242,9 +246,9 @@ impl Collection {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_note_maybe_with_fields(&self, id: NoteId, _with_fields: bool) -> Result<Note> {
|
fn get_note_maybe_with_fields(&self, id: NoteId, _with_fields: bool) -> Result<Note> {
|
||||||
// todo: After note.sort_field has been modified so it can be displayed in the browser,
|
// todo: After note.sort_field has been modified so it can be displayed in the
|
||||||
// we can update note_field_str() and only load the note with fields if a card render is
|
// browser, we can update note_field_str() and only load the note with
|
||||||
// necessary (see #1082).
|
// fields if a card render is necessary (see #1082).
|
||||||
if true {
|
if true {
|
||||||
self.storage.get_note(id)?
|
self.storage.get_note(id)?
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -449,8 +453,9 @@ impl RowContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the due date of the next due card that is not in a filtered deck, new, suspended or
|
/// Returns the due date of the next due card that is not in a filtered
|
||||||
/// buried or the empty string if there is no such card.
|
/// deck, new, suspended or buried or the empty string if there is no
|
||||||
|
/// such card.
|
||||||
fn note_due_str(&self) -> String {
|
fn note_due_str(&self) -> String {
|
||||||
self.cards
|
self.cards
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -461,7 +466,8 @@ impl RowContext {
|
||||||
.unwrap_or_else(|| "".into())
|
.unwrap_or_else(|| "".into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the average ease of the non-new cards or a hint if there aren't any.
|
/// Returns the average ease of the non-new cards or a hint if there aren't
|
||||||
|
/// any.
|
||||||
fn ease_str(&self) -> String {
|
fn ease_str(&self) -> String {
|
||||||
let eases: Vec<u16> = self
|
let eases: Vec<u16> = self
|
||||||
.cards
|
.cards
|
||||||
|
|
@ -476,7 +482,8 @@ impl RowContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the average interval of the review and relearn cards if there are any.
|
/// Returns the average interval of the review and relearn cards if there
|
||||||
|
/// are any.
|
||||||
fn interval_str(&self) -> String {
|
fn interval_str(&self) -> String {
|
||||||
if !self.notes_mode {
|
if !self.notes_mode {
|
||||||
match self.cards[0].ctype {
|
match self.cards[0].ctype {
|
||||||
|
|
|
||||||
|
|
@ -3,24 +3,27 @@
|
||||||
|
|
||||||
pub(crate) mod undo;
|
pub(crate) mod undo;
|
||||||
|
|
||||||
use std::collections::{hash_map::Entry, HashMap, HashSet};
|
use std::collections::hash_map::Entry;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use num_enum::TryFromPrimitive;
|
use num_enum::TryFromPrimitive;
|
||||||
use serde_repr::{Deserialize_repr, Serialize_repr};
|
use serde_repr::Deserialize_repr;
|
||||||
|
use serde_repr::Serialize_repr;
|
||||||
|
|
||||||
use crate::{
|
use crate::collection::Collection;
|
||||||
collection::Collection,
|
use crate::config::SchedulerVersion;
|
||||||
config::SchedulerVersion,
|
use crate::deckconfig::DeckConfig;
|
||||||
deckconfig::DeckConfig,
|
use crate::decks::DeckId;
|
||||||
decks::DeckId,
|
use crate::define_newtype;
|
||||||
define_newtype,
|
use crate::error::AnkiError;
|
||||||
error::{AnkiError, FilteredDeckError, Result},
|
use crate::error::FilteredDeckError;
|
||||||
notes::NoteId,
|
use crate::error::Result;
|
||||||
ops::StateChanges,
|
use crate::notes::NoteId;
|
||||||
prelude::*,
|
use crate::ops::StateChanges;
|
||||||
timestamp::TimestampSecs,
|
use crate::prelude::*;
|
||||||
types::Usn,
|
use crate::timestamp::TimestampSecs;
|
||||||
};
|
use crate::types::Usn;
|
||||||
|
|
||||||
define_newtype!(CardId, i64);
|
define_newtype!(CardId, i64);
|
||||||
|
|
||||||
|
|
@ -79,7 +82,8 @@ pub struct Card {
|
||||||
pub(crate) flags: u8,
|
pub(crate) flags: u8,
|
||||||
/// The position in the new queue before leaving it.
|
/// The position in the new queue before leaving it.
|
||||||
pub(crate) original_position: Option<u32>,
|
pub(crate) original_position: Option<u32>,
|
||||||
/// JSON object or empty; exposed through the reviewer for persisting custom state
|
/// JSON object or empty; exposed through the reviewer for persisting custom
|
||||||
|
/// state
|
||||||
pub(crate) custom_data: String,
|
pub(crate) custom_data: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -159,9 +163,10 @@ impl Card {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remaining steps after configured steps have changed, disregarding "remaining today".
|
/// Remaining steps after configured steps have changed, disregarding
|
||||||
/// [None] if same as before. A step counts as remaining if the card has not passed a step
|
/// "remaining today". [None] if same as before. A step counts as
|
||||||
/// with the same or a greater delay, but output will be at least 1.
|
/// remaining if the card has not passed a step with the same or a
|
||||||
|
/// greater delay, but output will be at least 1.
|
||||||
fn new_remaining_steps(&self, new_steps: &[f32], old_steps: &[f32]) -> Option<u32> {
|
fn new_remaining_steps(&self, new_steps: &[f32], old_steps: &[f32]) -> Option<u32> {
|
||||||
let remaining = self.remaining_steps();
|
let remaining = self.remaining_steps();
|
||||||
let new_remaining = old_steps
|
let new_remaining = old_steps
|
||||||
|
|
@ -387,10 +392,9 @@ impl<'a> RemainingStepsAdjuster<'a> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::tests::{
|
use crate::tests::open_test_collection_with_learning_card;
|
||||||
open_test_collection_with_learning_card, open_test_collection_with_relearning_card,
|
use crate::tests::open_test_collection_with_relearning_card;
|
||||||
DeckAdder,
|
use crate::tests::DeckAdder;
|
||||||
};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_increase_remaining_learning_steps_if_new_deck_has_more_unpassed_ones() {
|
fn should_increase_remaining_learning_steps_if_new_deck_has_more_unpassed_ones() {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::{pb, prelude::*};
|
use crate::pb;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
mod parser;
|
mod parser;
|
||||||
mod writer;
|
mod writer;
|
||||||
|
|
@ -92,7 +93,8 @@ pub fn anki_directive_benchmark() {
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Strip av tags and assert equality with input or separately passed output.
|
/// Strip av tags and assert equality with input or separately passed
|
||||||
|
/// output.
|
||||||
macro_rules! assert_av_stripped {
|
macro_rules! assert_av_stripped {
|
||||||
($input:expr) => {
|
($input:expr) => {
|
||||||
assert_eq!($input, strip_av_tags($input));
|
assert_eq!($input, strip_av_tags($input));
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,30 @@
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use nom::{
|
use nom::branch::alt;
|
||||||
branch::alt,
|
use nom::bytes::complete::is_not;
|
||||||
bytes::complete::{is_not, tag},
|
use nom::bytes::complete::tag;
|
||||||
character::complete::{anychar, multispace0},
|
use nom::character::complete::anychar;
|
||||||
combinator::{map, not, recognize, success, value},
|
use nom::character::complete::multispace0;
|
||||||
multi::{many0, many1},
|
use nom::combinator::map;
|
||||||
sequence::{delimited, pair, preceded, separated_pair, terminated, tuple},
|
use nom::combinator::not;
|
||||||
};
|
use nom::combinator::recognize;
|
||||||
|
use nom::combinator::success;
|
||||||
|
use nom::combinator::value;
|
||||||
|
use nom::multi::many0;
|
||||||
|
use nom::multi::many1;
|
||||||
|
use nom::sequence::delimited;
|
||||||
|
use nom::sequence::pair;
|
||||||
|
use nom::sequence::preceded;
|
||||||
|
use nom::sequence::separated_pair;
|
||||||
|
use nom::sequence::terminated;
|
||||||
|
use nom::sequence::tuple;
|
||||||
|
|
||||||
use super::{CardNodes, Directive, Node, OtherDirective, TtsDirective};
|
use super::CardNodes;
|
||||||
|
use super::Directive;
|
||||||
|
use super::Node;
|
||||||
|
use super::OtherDirective;
|
||||||
|
use super::TtsDirective;
|
||||||
|
|
||||||
type IResult<'a, O> = nom::IResult<&'a str, O>;
|
type IResult<'a, O> = nom::IResult<&'a str, O>;
|
||||||
|
|
||||||
|
|
@ -87,7 +101,8 @@ fn node(s: &str) -> IResult<Node> {
|
||||||
alt((text_node, sound_node, tag_node))(s)
|
alt((text_node, sound_node, tag_node))(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A sound tag `[sound:resource]`, where `resource` is pointing to a sound or video file.
|
/// A sound tag `[sound:resource]`, where `resource` is pointing to a sound or
|
||||||
|
/// video file.
|
||||||
fn sound_node(s: &str) -> IResult<Node> {
|
fn sound_node(s: &str) -> IResult<Node> {
|
||||||
map(
|
map(
|
||||||
delimited(tag("[sound:"), is_not("]"), tag("]")),
|
delimited(tag("[sound:"), is_not("]"), tag("]")),
|
||||||
|
|
@ -106,7 +121,8 @@ fn tag_node(s: &str) -> IResult<Node> {
|
||||||
fn opening_parser<'name, 's: 'name>(
|
fn opening_parser<'name, 's: 'name>(
|
||||||
name: &'name str,
|
name: &'name str,
|
||||||
) -> impl FnMut(&'s str) -> IResult<Vec<(&str, &str)>> + 'name {
|
) -> impl FnMut(&'s str) -> IResult<Vec<(&str, &str)>> + 'name {
|
||||||
/// List of whitespace-separated `key=val` tuples, where `val` may be empty.
|
/// List of whitespace-separated `key=val` tuples, where `val` may be
|
||||||
|
/// empty.
|
||||||
fn options(s: &str) -> IResult<Vec<(&str, &str)>> {
|
fn options(s: &str) -> IResult<Vec<(&str, &str)>> {
|
||||||
fn key(s: &str) -> IResult<&str> {
|
fn key(s: &str) -> IResult<&str> {
|
||||||
is_not("] \t\r\n=")(s)
|
is_not("] \t\r\n=")(s)
|
||||||
|
|
@ -136,7 +152,8 @@ fn tag_node(s: &str) -> IResult<Node> {
|
||||||
value((), tuple((tag("[/anki:"), tag(name), tag("]"))))
|
value((), tuple((tag("[/anki:"), tag(name), tag("]"))))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a parser to match and return anything until a closing `name` tag is found.
|
/// Return a parser to match and return anything until a closing `name` tag
|
||||||
|
/// is found.
|
||||||
fn content_parser<'parser, 'name: 'parser, 's: 'parser>(
|
fn content_parser<'parser, 'name: 'parser, 's: 'parser>(
|
||||||
name: &'name str,
|
name: &'name str,
|
||||||
) -> impl FnMut(&'s str) -> IResult<&str> + 'parser {
|
) -> impl FnMut(&'s str) -> IResult<&str> + 'parser {
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,15 @@
|
||||||
|
|
||||||
use std::fmt::Write as _;
|
use std::fmt::Write as _;
|
||||||
|
|
||||||
use super::{CardNodes, Directive, Node, OtherDirective, TtsDirective};
|
use super::CardNodes;
|
||||||
use crate::{
|
use super::Directive;
|
||||||
pb,
|
use super::Node;
|
||||||
prelude::*,
|
use super::OtherDirective;
|
||||||
text::{decode_entities, strip_html_for_tts},
|
use super::TtsDirective;
|
||||||
};
|
use crate::pb;
|
||||||
|
use crate::prelude::*;
|
||||||
|
use crate::text::decode_entities;
|
||||||
|
use crate::text::strip_html_for_tts;
|
||||||
|
|
||||||
impl<'a> CardNodes<'a> {
|
impl<'a> CardNodes<'a> {
|
||||||
pub(super) fn write_without_av_tags(&self) -> String {
|
pub(super) fn write_without_av_tags(&self) -> String {
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,23 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// Copyright: Ankitects Pty Ltd and contributors
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use std::{borrow::Cow, collections::HashSet, fmt::Write};
|
use std::borrow::Cow;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
use htmlescape::encode_attribute;
|
use htmlescape::encode_attribute;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use nom::{
|
use nom::branch::alt;
|
||||||
branch::alt,
|
use nom::bytes::complete::tag;
|
||||||
bytes::complete::{tag, take_while},
|
use nom::bytes::complete::take_while;
|
||||||
combinator::map,
|
use nom::combinator::map;
|
||||||
IResult,
|
use nom::IResult;
|
||||||
};
|
use regex::Captures;
|
||||||
use regex::{Captures, Regex};
|
use regex::Regex;
|
||||||
|
|
||||||
use crate::{latex::contains_latex, template::RenderContext, text::strip_html_preserving_entities};
|
use crate::latex::contains_latex;
|
||||||
|
use crate::template::RenderContext;
|
||||||
|
use crate::text::strip_html_preserving_entities;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref MATHJAX: Regex = Regex::new(
|
static ref MATHJAX: Regex = Regex::new(
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue