typescript_tools/
make_depend.rs1use std::collections::HashMap;
2use std::fmt::Display;
3use std::fs;
4use std::path::{Path, PathBuf};
5
6use pathdiff::diff_paths;
7use rinja::Template;
8
9use crate::configuration_file::ConfigurationFile;
10use crate::io::FromFileError;
11use crate::monorepo_manifest::{EnumeratePackageManifestsError, MonorepoManifest};
12use crate::package_manifest::PackageManifest;
13use crate::types::{Directory, PackageName};
14
15#[derive(Template)]
16#[template(path = "makefile")]
17
18struct MakefileTemplate<'a> {
19 monorepo_kind: &'a str,
20 root: &'a str,
21 output_file: &'a str,
22 package_directory: &'a str,
23 scoped_package_name: &'a PackageName,
24 unscoped_package_name: &'a str,
25 internal_dependency_package_json_filenames_inclusive: &'a Vec<String>,
26 create_pack_target: &'a bool,
27 npm_pack_archive_dependencies: &'a HashMap<String, String>,
28 internal_npm_dependencies_exclusive: &'a Vec<&'a str>,
29}
30
31#[derive(Debug)]
32#[non_exhaustive]
33pub struct MakeDependencyMakefileError {
34 pub kind: MakeDependencyMakefileErrorKind,
35}
36
37impl Display for MakeDependencyMakefileError {
38 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39 write!(f, "error creating package makefile")
40 }
41}
42
43impl std::error::Error for MakeDependencyMakefileError {
44 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
45 match &self.kind {
46 MakeDependencyMakefileErrorKind::FromFile(err) => Some(err),
47 MakeDependencyMakefileErrorKind::EnumeratePackageManifests(err) => Some(err),
48 }
49 }
50}
51
52impl From<FromFileError> for MakeDependencyMakefileError {
53 fn from(err: FromFileError) -> Self {
54 Self {
55 kind: MakeDependencyMakefileErrorKind::FromFile(err),
56 }
57 }
58}
59
60impl From<EnumeratePackageManifestsError> for MakeDependencyMakefileError {
61 fn from(err: EnumeratePackageManifestsError) -> Self {
62 Self {
63 kind: MakeDependencyMakefileErrorKind::EnumeratePackageManifests(err),
64 }
65 }
66}
67
68#[derive(Debug)]
69pub enum MakeDependencyMakefileErrorKind {
70 #[non_exhaustive]
71 FromFile(FromFileError),
72 #[non_exhaustive]
73 EnumeratePackageManifests(EnumeratePackageManifestsError),
74}
75
76pub fn make_dependency_makefile(
77 root: &Path,
78 package_directory: &Path,
79 output_file: &Path,
80 create_pack_target: bool,
81) -> Result<(), MakeDependencyMakefileError> {
82 let monorepo_manifest = MonorepoManifest::from_directory(root)?;
83 let package_manifest = PackageManifest::from_directory(
84 &monorepo_manifest.root,
85 Directory::unchecked_from_path(package_directory),
87 )?;
88
89 let package_manifest_by_package_name = monorepo_manifest.package_manifests_by_package_name()?;
91
92 let internal_dependencies_exclusive: Vec<_> = package_manifest
93 .transitive_internal_dependency_package_names_exclusive(&package_manifest_by_package_name)
94 .collect();
95
96 let internal_dependency_package_json_filenames_inclusive: Vec<PathBuf> = {
97 let mut dependency_dirs = internal_dependencies_exclusive
98 .iter()
99 .map(|internal_dependency| (*internal_dependency).path())
100 .collect::<Vec<_>>();
101 dependency_dirs.push(package_manifest.path());
102 dependency_dirs
103 };
104
105 let npm_pack_archive_dependencies = &internal_dependencies_exclusive
106 .iter()
107 .map(|dependency| {
108 let target_directory = package_manifest
109 .directory()
110 .join(".internal-npm-dependencies");
111 let target = target_directory
112 .join(dependency.npm_pack_file_basename())
113 .to_str()
114 .expect("npm pack filename is not UTF-8 encodable")
115 .to_owned();
116 let source_package_directory = dependency.directory();
117 let source = diff_paths(source_package_directory, target_directory)
118 .expect("No relative path to source package")
119 .to_str()
120 .expect("Source package path is not UTF-8 encodable")
121 .to_owned();
122 (target, source)
123 })
124 .collect();
125
126 let makefile_contents = MakefileTemplate {
128 monorepo_kind: monorepo_manifest.kind.into(),
129 root: root.to_str().expect("Monorepo root is not UTF_8 encodable"),
130 output_file: output_file
131 .to_str()
132 .expect("Output file is not UTF-8 encodable"),
133 package_directory: package_manifest
134 .directory()
135 .to_str()
136 .expect("Package directory is not UTF-8 encodable"),
137 scoped_package_name: &package_manifest.contents.name,
138 unscoped_package_name: package_manifest.unscoped_package_name(),
139 internal_dependency_package_json_filenames_inclusive:
140 &internal_dependency_package_json_filenames_inclusive
141 .iter()
142 .map(|internal_dependency| {
143 internal_dependency
144 .to_str()
145 .expect("Internal package directory is not UTF-8 encodable")
146 .to_owned()
147 })
148 .collect(),
149 create_pack_target: &create_pack_target,
150 npm_pack_archive_dependencies,
151 internal_npm_dependencies_exclusive: &npm_pack_archive_dependencies
152 .keys()
153 .map(String::as_str)
154 .collect::<Vec<_>>(),
155 }
156 .render()
157 .expect("Unable to render makefile template");
158
159 fs::write(package_directory.join(output_file), makefile_contents)
160 .expect("Unable to write makefile");
161
162 Ok(())
163}