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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
//! ref: composer/src/Composer/Command/BaseConfigCommand.php
use crate::command::base_command::{BaseCommand, BaseCommandData, HasBaseCommandData};
use crate::config::Config;
use crate::config::json_config_source::JsonConfigSource;
use crate::factory::Factory;
use crate::json::json_file::JsonFile;
use crate::util::platform::Platform;
use crate::util::silencer::Silencer;
use indexmap::IndexMap;
use shirabe_external_packages::symfony::component::console::input::input_interface::InputInterface;
use shirabe_external_packages::symfony::component::console::output::output_interface::OutputInterface;
use shirabe_php_shim::{PhpMixed, chmod, touch};
pub trait BaseConfigCommand: BaseCommand {
fn config(&self) -> Option<&std::rc::Rc<std::cell::RefCell<Config>>>;
fn config_mut(&mut self) -> &mut Option<std::rc::Rc<std::cell::RefCell<Config>>>;
fn config_file(&self) -> Option<&JsonFile>;
fn config_file_mut(&mut self) -> Option<&mut JsonFile>;
fn set_config_file(&mut self, file: Option<JsonFile>);
fn config_source(&self) -> Option<&JsonConfigSource>;
fn config_source_mut(&mut self) -> Option<&mut JsonConfigSource>;
fn set_config_source(&mut self, source: Option<JsonConfigSource>);
fn initialize(
&mut self,
input: &dyn InputInterface,
output: &dyn OutputInterface,
) -> anyhow::Result<()> {
// TODO(phase-b): BaseCommand::initialize chained via Self::initialize would recurse;
// omitted until trait disambiguation is sorted.
if input.get_option("global").as_bool().unwrap_or(false)
&& !input.get_option("file").is_null()
{
return Err(anyhow::anyhow!("--file and --global can not be combined"));
}
let io = self.get_io();
*self.config_mut() = Some(std::rc::Rc::new(std::cell::RefCell::new(
Factory::create_config(Some(&*io), None)?,
)));
let config_rc = std::rc::Rc::clone(self.config().unwrap());
// When using --global flag, set baseDir to home directory for correct absolute path resolution
if input.get_option("global").as_bool().unwrap_or(false) {
let home = config_rc.borrow_mut().get("home").to_string();
config_rc.borrow_mut().set_base_dir(Some(home));
}
let config_file = self.get_composer_config_file(input, &*config_rc.borrow());
// Create global composer.json if invoked using `composer global [config-cmd]`
if (config_file == "composer.json" || config_file == "./composer.json")
&& !std::path::Path::new(&config_file).exists()
&& std::fs::canonicalize(Platform::get_cwd(false)?).ok()
== std::fs::canonicalize(config_rc.borrow_mut().get("home").to_string()).ok()
{
std::fs::write(&config_file, "{\n}\n")?;
}
self.set_config_file(Some(JsonFile::new(
config_file.clone(),
None,
Some(io.clone_box()),
)?));
// TODO(phase-b): JsonConfigSource::new takes owned JsonFile, but PHP shares the same
// instance with $this->configFile. Needs Rc<RefCell<JsonFile>> refactor on both sides.
self.set_config_source(None);
// Initialize the global file if it's not there, ignoring any warnings or notices
if input.get_option("global").as_bool().unwrap_or(false)
&& !self.config_file().as_ref().unwrap().exists()
{
let path = self.config_file().as_ref().unwrap().get_path().to_string();
touch(&path);
self.config_file_mut()
.as_mut()
.unwrap()
.write(PhpMixed::Array({
let mut m = IndexMap::new();
m.insert(
"config".to_string(),
Box::new(PhpMixed::Array(IndexMap::new())),
);
m
}))?;
let _ = Silencer::call(|| {
chmod(&path, 0o600);
Ok(())
});
}
if !self.config_file().as_ref().unwrap().exists() {
return Err(anyhow::anyhow!(
"File \"{}\" cannot be found in the current directory",
config_file
));
}
Ok(())
}
/// Get the local composer.json, global config.json, or the file passed by the user
fn get_composer_config_file(&self, input: &dyn InputInterface, config: &Config) -> String {
if input.get_option("global").as_bool().unwrap_or(false) {
format!("{}/config.json", config.get("home"))
} else {
input
.get_option("file")
.as_string_opt()
.map(|s| s.to_string())
.unwrap_or_else(|| Factory::get_composer_file().unwrap_or_default())
}
}
/// Get the local auth.json or global auth.json, or if the user passed in a file to use,
/// the corresponding auth.json
fn get_auth_config_file(&self, input: &dyn InputInterface, config: &Config) -> String {
if input.get_option("global").as_bool().unwrap_or(false) {
format!("{}/auth.json", config.get("home"))
} else {
let composer_config = self.get_composer_config_file(input, config);
let parent = std::path::Path::new(&composer_config)
.parent()
.map(|p| p.to_string_lossy().to_string())
.unwrap_or_default();
format!("{}/auth.json", parent)
}
}
}
|