MobDev.Adopt.Generator (mob_dev v0.7.15)

Copy Markdown View Source

EEx-template assigns, native-tree template/static roots, dep resolution, and Pythonx wiring for mix mob.adopt.

Duplicated from MobNew.ProjectGenerator (mob_new, the project generator archive). Only the transitive closure mix mob.adopt exercises was copied — the full mix mob.new generation pipeline (generate/3, liveview_generate/3, the mix phx.new shell-out, the config/router patchers) stays in mob_new. Phase 5 of build_system_migration.md reunifies the two copies behind a single Igniter-based path; until then both repos carry their own copy (mob_new can't depend on mob_dev — it's a self-contained Mix archive; see ArchiveSelfContainedTest).

Native templates come from the installed mob_new archive

The Android/iOS native trees mob.adopt emits are rendered from mob_new's priv/templates/mob.new/ and priv/static/mob.new/. Those template files belong to the generator and are deliberately NOT duplicated here. By design, mix mob.adopt --android/--ios requires the mob_new archive installed (mix archive.install hex mob_new) in addition to mob_dev as a project dep — mob_new stays the single source of native templates, so the two can't drift. Mix puts an installed archive on the code path, so :code.priv_dir(:mob_new) resolves its bundled priv at runtime — the same way mob_new's own mix mob.new loads them. templates_root/1 / static_root/1 prefer that, then fall back to a local checkout via $MOB_NEW_DIR / ~/code/mob_new for development. See decisions/2026-06-19-mob-adopt-lives-in-mob_dev.md.

Compile-time regex

Compiles regexes at runtime via Regex.compile!/1, never ~r// literals (OTP 28.0 dropped :re.import/1). See mob AGENTS.md, pre-empt-failure rule "Compile-time ~r// literals are unsafe on OTP 28".

Summary

Functions

Patches a generated project to enable Pythonx (embedded CPython, iOS + Android).

Returns the EEx template assigns map for app_name.

Returns {mob_dep, mob_dev_dep, mob_local_dir}. mob_local_dir is the absolute mob checkout under --local (it belongs in the gitignored mob.local.exs, never the committed mob.exs), otherwise nil.

Functions

apply_python_patches(project_dir, app_name)

@spec apply_python_patches(String.t(), String.t()) :: :ok

Patches a generated project to enable Pythonx (embedded CPython, iOS + Android).

Two patches:

  • mix.exs — adds {:pythonx, "~> 0.4"} to deps.
  • lib/<app>/python_paths.ex — pure detection module that reads :code.root_dir/0 for iOS and MOB_PYTHON_HOME / MOB_PYTHON_DL env vars (set by Android's MainActivity) for Android.

Mirrors mix mob.enable pythonx. Idempotent — safe to run twice.

assigns(app_name, opts \\ [])

@spec assigns(
  String.t(),
  keyword()
) :: map()

Returns the EEx template assigns map for app_name.

Options:

  • :local — when true, generates path: deps pointing to local mob/mob_dev repos instead of hex version constraints. Paths are resolved from the MOB_DIR and MOB_DEV_DIR environment variables, falling back to ../mob and ../mob_dev relative to the generated project location.

bundle_prefix()

@spec bundle_prefix() :: String.t()

resolve_deps(opts)

@spec resolve_deps(keyword()) :: {String.t(), String.t(), String.t() | nil}

Returns {mob_dep, mob_dev_dep, mob_local_dir}. mob_local_dir is the absolute mob checkout under --local (it belongs in the gitignored mob.local.exs, never the committed mob.exs), otherwise nil.