欢迎关注公众号: 上篇介绍到:InfluxDB-IOx的环境搭建,详情见:https://my.oschina.net/u/3374539/blog/5016798 本章开始,讲解启动的主流程! 打开src/main.rs文件可以找到下面的代码 fn m…
上篇介绍到:InfluxDB-IOx的环境搭建,详情见:https://my.oschina.net/u/3374539/blog/5016798
本章开始,讲解启动的主流程!
打开
文件可以找到下面的代码
1 2 3 4 5 6 7 8 9 10 11 12 13
| fn main() -> Result<(), std::io::Error> { load_dotenv();
let config = Config::from_args(); println!("{:?}", config); ..... Ok(()) }
|
在
方法中映入眼帘的第一行就是
方法,然后是
接下来就分别跟踪这两个方法,看明白是怎么工作的。
加载配置文件
在
文件中,我们可以看到这样一行:
意思就是这个工程使用的配置文件,名字是
。了解这个特殊的名字之后,我们看代码
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| fn load_dotenv() { match dotenv() { Ok(_) => {} Err(dotenv::Error::Io(err)) if err.kind() == std::io::ErrorKind::NotFound => { } Err(e) => { eprintln!("FATAL Error loading config from: {}", e); eprintln!("Aborting"); std::process::exit(1); } }; }
|
然后跟踪
方法看看如何执行(这里就进入了dotenv这个crate了):
1
| 为了方便写,我就直接把所有调用,从上到下的顺序全都写出来了
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| pub fn dotenv() -> Result<PathBuf> { let (path, iter) = Finder::new().find()?; iter.load()?; Ok(path) }
pub fn new() -> Self { Finder { filename: Path::new(".env"), } }
pub fn find(self) -> Result<(PathBuf, Iter<File>)> { let path = find(&env::current_dir().map_err(Error::Io)?, self.filename)?; let file = File::open(&path).map_err(Error::Io)?; let iter = Iter::new(file); Ok((path, iter)) } pub fn find(directory: &Path, filename: &Path) -> Result<PathBuf> { let candidate = directory.join(filename); match fs::metadata(&candidate) { Ok(metadata) => if metadata.is_file() { return Ok(candidate); }, Err(error) => { if error.kind() != io::ErrorKind::NotFound { return Err(Error::Io(error)); } } } if let Some(parent) = directory.parent() { find(parent, filename) } else { Err(Error::Io(io::Error::new(io::ErrorKind::NotFound, "path not found"))) } }
pub fn load(self) -> Result<()> { for item in self { let (key, value) = item?; if env::var(&key).is_err() { env::set_var(&key, value); } } Ok(()) }
impl<R: Read> Iterator for Iter<R> { type Item = Result<(String, String)>;
fn next(&mut self) -> Option<Self::Item> { loop { let line = match self.lines.next() { Some(Ok(line)) => line, Some(Err(err)) => return Some(Err(Error::Io(err))), None => return None, }; match parse::parse_line(&line, &mut self.substitution_data) { Ok(Some(result)) => return Some(Ok(result)), Ok(None) => {} Err(err) => return Some(Err(err)), } } } }
|
研究这里的时候,我发现了一个比较好玩儿的东西就是返回值的
���标准库的定义中,Result是有两个值,分别是<T,E>。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| 自定义的类型,节省了Error这个模板代码 pub type Result<T> = std::result::Result<T, Error>;
pub enum Error { LineParse(String, usize), Io(io::Error), EnvVar(std::env::VarError), #[doc(hidden)] __Nonexhaustive }
impl Error { pub fn not_found(&self) -> bool { if let Error::Io(ref io_error) = *self { return io_error.kind() == io::ErrorKind::NotFound; } false } }
impl error::Error for Error { fn source(&self) -> Option<&(dyn error::Error + 'static)> { match self { Error::Io(err) => Some(err), Error::EnvVar(err) => Some(err), _ => None, } } } //实现错误的打印 impl fmt::Display for Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { Error::Io(err) => write!(fmt, "{}", err), Error::EnvVar(err) => write!(fmt, "{}", err), Error::LineParse(line, error_index) => write!(fmt, "Error parsing line: '{}', error at line index: {}", line, error_index), _ => unreachable!(), } } }
|
更详细的rust错误处理,可以参见:https://zhuanlan.zhihu.com/p/109242831
命令行参数
在main方法中我们可以看到第二行,
1 2
| let config = Config::from_args();
|
这是
使用了
这个
,调用该方法后,程序会根据结构体上的
中的参数进行执行命令行解析。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| #[derive(Debug, StructOpt)] #[structopt(
name = "influxdb_iox",
about = "InfluxDB IOx server and command line tools", long_about = )] struct Config { #[structopt(short, long, parse(from_occurrences))] verbose: u64, #[structopt( short, long, global = true, env = "IOX_ADDR", default_value = "http://127.0.0.1:8082" )] host: String, #[structopt(long)] num_threads: Option<usize>, #[structopt(subcommand)] command: Command, }
#[derive(Debug, StructOpt)] enum Command { Convert { Meta { Database(commands::database::Config), Run(Box<commands::run::Config>), Stats(commands::stats::Config), Server(commands::server::Config), Writer(commands::writer::Config), Operation(commands::operations::Config), }
|
下面通过打印出来的例子来对应
中的内容。
1 2 3
| $ ./influxdb_iox -vvvv run Config { verbose: 4, host: "http://127.0.0.1:8082", num_threads: None, command: Run(Config { rust_log: None, log_format: None, verbose_count: 0, writer_id: None, http_bind_address: 127.0.0.1:8080, grpc_bind_address: 127.0.0.1:8082, database_directory: None, object_store: None, bucket: None, aws_access_key_id: None, aws_secret_access_key: None, aws_default_region: "us-east-1", google_service_account: None, azure_storage_account: None, azure_storage_access_key: None, jaeger_host: None }) }
|
可以看到,我们执行了
这个变体的
,并且指定了
结构体中的
4 次,
也成功的识别了。
后面继续学习程序的启动过程,祝玩儿的开心!
本文标题: 时序数据库Influx-IOx源码学习三(命令行及配置)
本文作者: OSChina
发布时间: 2021年04月15日 09:46
最后更新: 2025年04月03日 11:07
原始链接: https://haoxiang.eu.org/35be3808/
版权声明: 本文著作权归作者所有,均采用CC BY-NC-SA 4.0许可协议,转载请注明出处!