Repository: ariga/atlas
Pull request #448 (2022-01-20 09:09:36)

doc: add explanation on binary contents


Patch:
diff --git a/cmd/atlas/doc.tmpl b/cmd/atlas/doc.tmpl
index 85a91b19..1701992a 100644
--- a/cmd/atlas/doc.tmpl
+++ b/cmd/atlas/doc.tmpl
@@ -15,6 +15,20 @@ flags.
 For a more detailed introduction to the CLI capabilities, head over to the
 [Getting Started](/cli/getting-started/setting-up) page.
 
+## Distributed Binaries
+
+Starting [v0.3.0](https://github.com/ariga/atlas/releases/tag/v0.3.0),
+ֿthe distributed binaries include code for a [Management UI](ui/intro.md) wrapping the
+core atlas functionality that is not currently released publicly. The binaries
+themselves are still released under the same [Apache License 2.0](https://github.com/ariga/atlas/blob/master/LICENSE).
+
+### Buliding from Source
+
+If you would like to build Atlas from source without the UI code run:
+```shell
+go build ./cmd/atlas
+```
+
 {{- range .Blocks }}
 {{ header .Depth }} {{ .CommandPath }}
 
diff --git a/doc/md/about.md b/doc/md/about.md
new file mode 100644
index 00000000..f4d666c0
--- /dev/null
+++ b/doc/md/about.md
@@ -0,0 +1,17 @@
+---
+title: About
+id: about
+slug: /about
+---
+# About Atlas
+
+<img src="https://atlasgo.io/uploads/gopher.svg" width="200" /> 
+
+Atlas is an open-source project maintained by [Ariga Technologies Ltd](https://ariga.io),
+a tech company founded by the maintainers of [Ent](https://entgo.io).
+
+### Reaching Out
+
+If you have a question or want to chat with the Atlas community, 
+join our [Discord Server](https://discord.com/invite/QhsmBAWzrC) or 
+[open an issue](https://github.com/ariga/atlas/issues) on our [GitHub Repo](https://github.com/ariga/atlas).
\ No newline at end of file
diff --git a/doc/md/cli.md b/doc/md/cli.md
index b7f98354..913e2ded 100644
--- a/doc/md/cli.md
+++ b/doc/md/cli.md
@@ -10,7 +10,21 @@ Similar information can be obtained by running any atlas command with the `-h` o
 flags.
 
 For a more detailed introduction to the CLI capabilities, head over to the
-[Getting Started](/cli/getting-started/setting-up) page.
+[Getting Started](getting-started/01-introduction.mdx) page.
+
+## Distributed Binaries
+
+Starting [v0.3.0](https://github.com/ariga/atlas/releases/tag/v0.3.0),
+ֿthe distributed binaries include code for a [Management UI](ui/intro.md) wrapping the
+core Atlas engine that is not currently released publicly. The binaries
+themselves are still released under the same [Apache License 2.0](https://github.com/ariga/atlas/blob/master/LICENSE).
+
+### Buliding from Source
+
+If you would like to build Atlas from source without the UI code run:
+```shell
+go get ariga.io/atlas/cmd/atlas
+```
 ## atlas env
 
 Print atlas environment variables.
diff --git a/doc/md/getting-started/01-introduction.mdx b/doc/md/getting-started/01-introduction.mdx
index fa960942..c27d1917 100644
--- a/doc/md/getting-started/01-introduction.mdx
+++ b/doc/md/getting-started/01-introduction.mdx
@@ -62,16 +62,19 @@ sudo install -o root -g root -m 0755 ./atlas-linux-amd64-v0.3.0 /usr/local/bin/a
 </TabItem>
 <TabItem value="windows">
 
-Download latest release.
-```shell
-curl -LO https://release.ariga.io/atlas/atlas-windows-amd64-v0.3.0.exe
-```
-Move the atlas binary to a file location on your system PATH.
+Download the [latest release](https://release.ariga.io/atlas/atlas-windows-amd64-v0.3.0.exe) and
+move the atlas binary to a file location on your system PATH.
 
 
 </TabItem>
 </Tabs>
 
+Starting with release [v0.3.0](https://github.com/ariga/atlas/releases/tag/v0.3.0),
+ֿthe distributed binaries include code for a [Management UI](../ui/intro.md) wrapping the
+core Atlas engine that is not currently released publicly. The binaries
+themselves are still released under the same [Apache License 2.0](https://github.com/ariga/atlas/blob/master/LICENSE).
+If you would like to build Atlas from source without the UI follow the instructions [here](../cli.md#building-from-source).
+
 To verify that the CLI is installed correctly run:
 ```shell
 atlas
diff --git a/doc/md/ui/intro.md b/doc/md/ui/intro.md
index 36cf6164..a71e8a06 100644
--- a/doc/md/ui/intro.md
+++ b/doc/md/ui/intro.md
@@ -1,7 +1,7 @@
 ---
 id: atlas-ui-intro
 slug: /ui/intro
-title: Atlas UI
+title: Management UI
 ---
 
 To launch the Atlas UI, run either `schema inspect` or `schema apply` commands with the `-w` command-line
@@ -19,4 +19,3 @@ atlas schema inspect -d "mysql://root:pass@tcp(localhost:3306)/example" -w
 atlas schema apply -d "mysql://root:pass@tcp(localhost:3306)/example" -f atlas.hcl -w
 ```
 
-
diff --git a/doc/website/docusaurus.config.js b/doc/website/docusaurus.config.js
index 0cf5e797..11c14598 100644
--- a/doc/website/docusaurus.config.js
+++ b/doc/website/docusaurus.config.js
@@ -48,6 +48,7 @@ module.exports = {
             {"label": "Getting Started", "to": "cli/getting-started/setting-up"},
             {"label": "Data Definition Language ", "to": "ddl/intro"},
             {"label": "CLI Reference", "to": "cli/reference"},
+            {"label": "About", "to": "about"},
           ]
         },
         {
diff --git a/doc/website/sidebars.js b/doc/website/sidebars.js
index 4c015d31..ab28326e 100644
--- a/doc/website/sidebars.js
+++ b/doc/website/sidebars.js
@@ -37,9 +37,15 @@ module.exports = {
         {
             type: 'doc',
             id: 'ui/atlas-ui-intro',
-        },
+        }
     ],
-
+    aboutSidebar: [
+        {
+            type: 'doc',
+            label: 'About',
+            id: 'about',
+        }
+    ]
     // But you can create a sidebar manually
     /*
     tutorialSidebar: [
diff --git a/doc/website/src/pages/index.js b/doc/website/src/pages/index.js
index dfdaa13e..c491b827 100644
--- a/doc/website/src/pages/index.js
+++ b/doc/website/src/pages/index.js
@@ -7,14 +7,14 @@ import GithubIcon from '../assets/icons/github.svg';
 import DiscordIcon from '../assets/icons/discord.svg';
 import BrowserOnly from "@docusaurus/core/lib/client/exports/BrowserOnly";
 
-function Chip({ text }) {
+function Chip({text}) {
     return <div className={index.chip}>
         {text}
     </div>
 }
 
 function Nav() {
-    return  <ul className={index.nav}>
+    return <ul className={index.nav}>
         <li className={index.linkItem}>
             <Link to={"/cli/getting-started/setting-up"}>
                 Getting Started
@@ -30,30 +30,29 @@ function Nav() {
                 GoDoc
             </Link>
         </li>
-
     </ul>
 }
 
 function SocialLinks() {
     return <div className={index.socialLinks}>
         <a href="https://github.com/ariga/atlas" target="_blank">
-            <GithubIcon />
+            <GithubIcon/>
         </a>
 
         <a href="https://discord.com/invite/QhsmBAWzrC" target="_blank">
-            <DiscordIcon />
+            <DiscordIcon/>
         </a>
     </div>
 }
 
 function Header() {
     return <div className={index.header}>
-        <Nav />
-        <SocialLinks />
+        <Nav/>
+        <SocialLinks/>
     </div>
 }
 
-function AtlasButton({ link, text, type, style }) {
+function AtlasButton({link, text, type, style}) {
     return (
         <button style={{...style}} className={index[type]}>
             <a className={index[`${type}Text`]} href={link}>{text}</a>
@@ -64,15 +63,17 @@ function AtlasButton({ link, text, type, style }) {
 export default function () {
     return <LayoutProviders>
         {/* first slide */}
-        <div id="slide1" className={index.slide1} style={{backgroundImage:'url(https://atlasgo.io/uploads/landing/background.png)'}}>
-            <Header />
+        <div id="slide1" className={index.slide1}
+             style={{backgroundImage: 'url(https://atlasgo.io/uploads/landing/background.png)'}}>
+            <Header/>
             <div className={index.rowContainer}>
                 <div className={index.slide1LeftSide}>
                     <div className={index.fullWidthSection}>
                         <h2 className={index.title}
-                            style={{ color: "#82C7FF" }}>Manage your <br /> database schemas with <span style={{ color: "white" }}>Atlas CLI</span></h2>
+                            style={{color: "#82C7FF"}}>Manage your <br/> database schemas with <span
+                            style={{color: "white"}}>Atlas CLI</span></h2>
 
-                        <p className={index.paragraph} style={{ color: "#DFF1FF", textAlign: "left", width: "90%" }}>
+                        <p className={index.paragraph} style={{color: "#DFF1FF", textAlign: "left", width: "90%"}}>
                             Atlas CLI is an open source tool that helps developers
                             manage their database schemas by applying modern
                             DevOps principles. Contrary to existing tools, Atlas
@@ -80,7 +81,8 @@ export default function () {
                             on your desired state.
                         </p>
                     </div>
-                    <AtlasButton style={{"marginTop": "5%"}} text="Get Started"  link="/cli/getting-started/setting-up" type="primaryButton"/>
+                    <AtlasButton style={{"marginTop": "5%"}} text="Get Started" link="/cli/getting-started/setting-up"
+                                 type="primaryButton"/>
                 </div>
                 <div className={index.imageContainer}>
                     <img src="https://atlasgo.io/uploads/hero2.png" alt="hero"/>
@@ -92,11 +94,11 @@ export default function () {
         <div className={index.slide2}>
             <div className={index.container}>
                 <section className={index.sectionNoMargin}>
-                    <h2 className={index.titleSecondary} style={{ textAlign: "center"}}>
+                    <h2 className={index.titleSecondary} style={{textAlign: "center"}}>
                         Define your schemas using the <span style={{color: "#2064E9"}}>Atlas DDL</span>
                     </h2>
                     <p className={index.paragraphSecondary}
-                       style={{ color: "#757889" }}>
+                       style={{color: "#757889"}}>
                         Atlas DDL is a declarative, Terraform-like configuration language designed to capture an
                         organization’s data topology. Currently, it supports defining schemas for SQL databases such as
                         MySQL, Postgres, SQLite and MariaDB.
@@ -111,22 +113,23 @@ export default function () {
                     {() => {
                         const mobile = window.innerWidth < 768;
                         const erdImage = mobile ? "https://atlasgo.io/uploads/images/erd-mobile.png" : "https://atlasgo.io/uploads/erd-180122.png";
-                        return <img style={{margin: "20px 0" }} src={erdImage} alt="erd"/>
+                        return <img style={{margin: "20px 0"}} src={erdImage} alt="erd"/>
                     }}
                 </BrowserOnly>
 
-                <section className={index.section} style={{ marginTop: "10px" }}>
-                   <h2 className={index.titleSecondary} style={{ textAlign: "center" }}>
-                       Visualize your schemas <br/> using the <span style={{color: "#2064E9"}}>Atlas UI</span>
-                   </h2>
-                   <p className={index.paragraphSecondary}
-                      style={{ color: "#757889" }}>
-                       With a single command-line flag, Atlas opens up as a rich user interface to visualize and manage your data topology.
-                   </p>
-               </section>
+                <section className={index.section} style={{marginTop: "10px"}}>
+                    <h2 className={index.titleSecondary} style={{textAlign: "center"}}>
+                        Visualize your schemas <br/> using the <span style={{color: "#2064E9"}}>Atlas UI</span>
+                    </h2>
+                    <p className={index.paragraphSecondary}
+                       style={{color: "#757889"}}>
+                        With a single command-line flag, Atlas opens up as a rich user interface to visualize and manage
+                        your data topology.
+                    </p>
+                </section>
                 <AtlasButton text="Get Started" link="/ui/intro" type="secondaryButton"/>
 
-                <img  className={index.dashboardImage} src="https://atlasgo.io/uploads/atlas-ui-180122.png" alt="ent"/>
+                <img className={index.dashboardImage} src="https://atlasgo.io/uploads/atlas-ui-180122.png" alt="ent"/>
             </div>
         </div>
 
@@ -134,26 +137,30 @@ export default function () {
         <div className={index.slide4}>
             <div className={index.container}>
                 <section className={index.section}>
-                    <h1 className={index.titleSecondary}>Migrate,&nbsp;<span style={{color: "#2064E9"}}>your way.</span></h1>
-                    <p className={index.paragraphSecondary}>Atlas provides the user with two types of migrations - declarative and versioned.</p>
-               </section>
+                    <h1 className={index.titleSecondary}>Migrate,&nbsp;<span style={{color: "#2064E9"}}>your way.</span>
+                    </h1>
+                    <p className={index.paragraphSecondary}>Atlas provides the user with two types of migrations -
+                        declarative and versioned.</p>
+                </section>
 
                 <section className={index.section}>
                     <h2 className={index.subtitle}>Declarative Migrations</h2>
-                    <p className={index.paragraphSecondary}>Declarative migrations are migrations in which the user provides the desired state, and Atlas gets your schema there instantly.</p>
+                    <p className={index.paragraphSecondary}>Declarative migrations are migrations in which the user
+                        provides the desired state, and Atlas gets your schema there instantly.</p>
                 </section>
 
                 <section className={index.section}>
                     <div className={index.subtitleWithChipWrapper}>
-                        <h2 style={{ marginRight: "10px" }} className={index.subtitleMargin}>Versioned Migrations</h2>
-                        <Chip text="Coming soon" />
+                        <h2 style={{marginRight: "10px"}} className={index.subtitleMargin}>Versioned Migrations</h2>
+                        <Chip text="Coming soon"/>
                     </div>
-                    <p className={index.paragraphSecondary}>Atlas offers you an alternative workflow, in which migrations are explicitly defined and
+                    <p className={index.paragraphSecondary}>Atlas offers you an alternative workflow, in which
+                        migrations are explicitly defined and
                         assigned a version. Atlas can then bring a schema to the desired version by following
                         the migrations between the current version and the specified one.</p>
                 </section>
             </div>
         </div>
-        <Footer />
+        <Footer/>
     </LayoutProviders>
 }
diff --git a/schema/schemaspec/schemahcl/hcl.go b/schema/schemaspec/schemahcl/hcl.go
index ffc0b428..21e6b6be 100644
--- a/schema/schemaspec/schemahcl/hcl.go
+++ b/schema/schemaspec/schemahcl/hcl.go
@@ -255,6 +255,11 @@ func (s *state) writeAttr(attr *schemaspec.Attr, body *hclwrite.Body) error {
 		expr := strings.ReplaceAll(v.V, "$", "")
 		body.SetAttributeRaw(attr.K, hclRawTokens(expr))
 	case *schemaspec.Type:
+		if v.IsRef {
+			expr := strings.ReplaceAll(v.T, "$", "")
+			body.SetAttributeRaw(attr.K, hclRawTokens(expr))
+			break
+		}
 		spec, ok := s.findTypeSpec(v.T)
 		if !ok {
 			v := fmt.Sprintf("sql(%q)", v.T)
diff --git a/sql/internal/specutil/convert.go b/sql/internal/specutil/convert.go
index 03f242c7..6e3727a5 100644
--- a/sql/internal/specutil/convert.go
+++ b/sql/internal/specutil/convert.go
@@ -302,7 +302,7 @@ func FromSchema(s *schema.Schema, fn TableSpecFunc) (*sqlspec.Schema, []*sqlspec
 			return nil, nil, err
 		}
 		if s.Name != "" {
-			table.Schema = schemaRef(s.Name)
+			table.Schema = SchemaRef(s.Name)
 		}
 		tables = append(tables, table)
 	}
@@ -501,7 +501,8 @@ func colRef(cName string, tName string) *schemaspec.Ref {
 	}
 }
 
-func schemaRef(n string) *schemaspec.Ref {
+// SchemaRef returns the schemaspec.Ref to the schema with the given name.
+func SchemaRef(n string) *schemaspec.Ref {
 	return &schemaspec.Ref{V: "$schema." + n}
 }
 
diff --git a/sql/postgres/sqlspec.go b/sql/postgres/sqlspec.go
index 8b062b0d..d29f458d 100644
--- a/sql/postgres/sqlspec.go
+++ b/sql/postgres/sqlspec.go
@@ -63,7 +63,31 @@ func UnmarshalSpec(data []byte, unmarshaler schemaspec.Unmarshaler, v interface{
 
 // MarshalSpec marshals v into an Atlas DDL document using a schemaspec.Marshaler.
 func MarshalSpec(v interface{}, marshaler schemaspec.Marshaler) ([]byte, error) {
-	return specutil.Marshal(v, marshaler, schemaSpec)
+	var d doc
+	switch s := v.(type) {
+	case *schema.Schema:
+		var err error
+		doc, err := schemaSpec(s)
+		if err != nil {
+			return nil, fmt.Errorf("specutil: failed converting schema to spec: %w", err)
+		}
+		d.Tables = doc.Tables
+		d.Schemas = doc.Schemas
+		d.Enums = doc.Enums
+	case *schema.Realm:
+		for _, s := range s.Schemas {
+			doc, err := schemaSpec(s)
+			if err != nil {
+				return nil, fmt.Errorf("specutil: failed converting schema to spec: %w", err)
+			}
+			d.Tables = append(d.Tables, doc.Tables...)
+			d.Schemas = append(d.Schemas, doc.Schemas...)
+			d.Enums = append(d.Enums, doc.Enums...)
+		}
+	default:
+		return nil, fmt.Errorf("specutil: failed marshaling spec. %T is not supported", v)
+	}
+	return marshaler.MarshalSpec(&d)
 }
 
 // Realm converts the schemas and tables of the doc into a schema.Realm.
@@ -216,9 +240,34 @@ func enumName(ref *schemaspec.Type) (string, error) {
 	return s[1], nil
 }
 
+// enumRef returns a reference string to the given enum name.
+func enumRef(n string) *schemaspec.Ref {
+	return &schemaspec.Ref{
+		V: "$enum." + n,
+	}
+}
+
 // schemaSpec converts from a concrete Postgres schema to Atlas specification.
-func schemaSpec(schem *schema.Schema) (*sqlspec.Schema, []*sqlspec.Table, error) {
-	return specutil.FromSchema(schem, tableSpec)
+func schemaSpec(schem *schema.Schema) (*doc, error) {
+	var d doc
+	s, tbls, err := specutil.FromSchema(schem, tableSpec)
+	if err != nil {
+		return nil, err
+	}
+	d.Schemas = []*sqlspec.Schema{s}
+	d.Tables = tbls
+	for _, t := range schem.Tables {
+		for _, c := range t.Columns {
+			if t, ok := c.Type.Type.(*schema.EnumType); ok {
+				d.Enums = append(d.Enums, &Enum{
+					Name:   t.T,
+					Schema: specutil.SchemaRef(s.Name),
+					Values: t.Values,
+				})
+			}
+		}
+	}
+	return &d, nil
 }
 
 // tableSpec converts from a concrete Postgres sqlspec.Table to a schema.Table.
@@ -240,6 +289,13 @@ func columnSpec(col *schema.Column, _ *schema.Table) (*sqlspec.Column, error) {
 
 // columnTypeSpec converts from a concrete Postgres schema.Type into sqlspec.Column Type.
 func columnTypeSpec(t schema.Type) (*sqlspec.Column, error) {
+	// Handle postgres enum types. They cannot be put into the TypeRegistry since their name is dynamic.
+	if e, ok := t.(*schema.EnumType); ok {
+		return &sqlspec.Column{Type: &schemaspec.Type{
+			T:     enumRef(e.T).V,
+			IsRef: true,
+		}}, nil
+	}
 	st, err := TypeRegistry.Convert(t)
 	if err != nil {
 		return nil, err


Test patch:
diff --git a/sql/postgres/sqlspec_test.go b/sql/postgres/sqlspec_test.go
index 80682f4e..694af026 100644
--- a/sql/postgres/sqlspec_test.go
+++ b/sql/postgres/sqlspec_test.go
@@ -201,6 +201,36 @@ enum "account_type" {
 	require.EqualValues(t, exp, &s)
 }
 
+func TestMarshalSpec_Enum(t *testing.T) {
+	s := schema.New("test").
+		AddTables(
+			schema.NewTable("account").
+				AddColumns(
+					schema.NewEnumColumn("account_type",
+						schema.EnumName("account_type"),
+						schema.EnumValues("private", "business"),
+					),
+				),
+		)
+	buf, err := MarshalSpec(s, hclState)
+	require.NoError(t, err)
+	const expected = `table "account" {
+  schema = schema.test
+  column "account_type" {
+    null = false
+    type = enum.account_type
+  }
+}
+schema "test" {
+}
+enum "account_type" {
+  schema = schema.test
+  values = ["private", "business", ]
+}
+`
+	require.EqualValues(t, expected, string(buf))
+}
+
 func TestTypes(t *testing.T) {
 	// TODO(rotemtam): enum, timestamptz, interval
 	for _, tt := range []struct {