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
use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;

use anyhow::Result;

use askama::Template;

use pathdiff::diff_paths;

use crate::configuration_file::ConfigurationFile;
use crate::monorepo_manifest::MonorepoManifest;
use crate::package_manifest::PackageManifest;

#[derive(Template)]
#[template(path = "makefile")]

struct MakefileTemplate<'a> {
    root: &'a str,
    output_file: &'a str,
    package_directory: &'a str,
    scoped_package_name: &'a str,
    unscoped_package_name: &'a str,
    internal_dependency_package_json_filenames_inclusive: &'a Vec<String>,
    create_pack_target: &'a bool,
    npm_pack_archive_dependencies: &'a HashMap<String, String>,
    internal_npm_dependencies_exclusive: &'a Vec<&'a str>,
}

pub fn make_dependency_makefile(opts: crate::opts::MakeDepend) -> Result<()> {
    let lerna_manifest = MonorepoManifest::from_directory(&opts.root)?;
    let package_manifest = PackageManifest::from_directory(&opts.root, &opts.package_directory)?;

    // determine the complete set of internal dependencies (and self!)
    let package_manifest_by_package_name = lerna_manifest.package_manifests_by_package_name()?;

    let internal_dependencies_exclusive = package_manifest
        .transitive_internal_dependency_package_names_exclusive(&package_manifest_by_package_name);

    let internal_dependency_package_json_filenames_inclusive: Vec<PathBuf> = {
        let mut dependency_dirs = internal_dependencies_exclusive
            .iter()
            .map(|internal_dependency| (*internal_dependency).path())
            .collect::<Vec<_>>();
        dependency_dirs.push(package_manifest.path());
        dependency_dirs
    };

    let npm_pack_archive_dependencies = &internal_dependencies_exclusive
        .iter()
        .map(|dependency| {
            let target_directory = package_manifest
                .directory()
                .join(".internal-npm-dependencies");
            let target = target_directory
                .join(dependency.npm_pack_file_basename())
                .to_str()
                .expect("npm pack filename is not UTF-8 encodable")
                .to_owned();
            let source_package_directory = dependency.directory();
            let source = diff_paths(source_package_directory, target_directory)
                .expect("No relative path to source package")
                .to_str()
                .expect("Source package path is not UTF-8 encodable")
                .to_owned();
            (target, source)
        })
        .collect();

    // create a string of the makefile contents
    let makefile_contents = MakefileTemplate {
        root: opts
            .root
            .to_str()
            .expect("Monorepo root is not UTF_8 encodable"),
        output_file: opts
            .output_file
            .to_str()
            .expect("Output file is not UTF-8 encodable"),
        package_directory: package_manifest
            .directory()
            .to_str()
            .expect("Package directory is not UTF-8 encodable"),
        scoped_package_name: &package_manifest.contents.name,
        unscoped_package_name: package_manifest.unscoped_package_name(),
        internal_dependency_package_json_filenames_inclusive:
            &internal_dependency_package_json_filenames_inclusive
                .iter()
                .map(|internal_dependency| {
                    internal_dependency
                        .to_str()
                        .expect("Internal package directory is not UTF-8 encodable")
                        .to_owned()
                })
                .collect(),
        create_pack_target: &opts.create_pack_target,
        npm_pack_archive_dependencies,
        internal_npm_dependencies_exclusive: &npm_pack_archive_dependencies
            .keys()
            .map(|string| string.as_str())
            .collect::<Vec<_>>(),
    }
    .render()
    .expect("Unable to render makefile template");

    fs::write(
        opts.package_directory.join(opts.output_file),
        makefile_contents,
    )
    .expect("Unable to write makefile");

    Ok(())
}