├── LICENSE.txt
├── package.json
├── design_docs.md
├── README.md
└── apex-source-control
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 http://ntree.com/
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "apex-source-control",
3 | "version": "1.4.2",
4 | "description": "Scripts for bringing Oracle Application Express apps into source control",
5 | "bin": {
6 | "apex-source-control": "apex-source-control"
7 | },
8 | "scripts": {
9 | "apex-to-file": "apex-source-control apex-to-file",
10 | "file-to-apex": "apex-source-control file-to-apex",
11 | "new-conf-file": "apex-source-control new-conf-file",
12 | "switch-conf-file": "apex-source-control switch-conf-file",
13 | "read-conf-file": "apex-source-control read-conf-file",
14 | "generate-app-id": "apex-source-control generate-app-id",
15 | "uninstall-apex": "apex-source-control uninstall-apex"
16 | },
17 | "repository": {
18 | "type": "git",
19 | "url": "git+https://github.com/ntreeinc/apex-source-control.git"
20 | },
21 | "keywords": [
22 | "oracle",
23 | "apex",
24 | "application",
25 | "express",
26 | "version",
27 | "source",
28 | "control"
29 | ],
30 | "author": "Ntree Inc. (http://ntree.com/)",
31 | "contributors": [
32 | "Nathan Farrant-Diaz (https://github.com/nfarrantdiaz)"
33 | ],
34 | "license": "MIT",
35 | "bugs": {
36 | "url": "https://github.com/ntreeinc/apex-source-control#known-issues"
37 | },
38 | "homepage": "https://github.com/ntreeinc/apex-source-control"
39 | }
40 |
--------------------------------------------------------------------------------
/design_docs.md:
--------------------------------------------------------------------------------
1 | **The problem**:
2 |
3 | There is a common practice of not placing databases or back-end applications under source-control management (SCM). APEX is web application development tool designed for back-end developers with limited front-end experience so the culture of ignoring SCM permeates into the development process. This tool aims to make integrating APEX apps with SCM a painless process.
4 |
5 |
6 | **System requirements for use**:
7 |
8 | - A Linux or Mac OSX environment
9 | - Downloaded APEX 5.0 files or above
10 | - An `export APEX_HOME` with `$APEX_HOME/utilities/oracle/apex/*.class` being the location of the above mentioned files
11 | - An installation of Oracle Instant Client
12 | - An `export ORACLE_HOME` with an existing `$ORACLE_HOME/jdbc/lib/jdbc6.jar` (likely included in installation of Oracle Instant Client)
13 | - `sqlplus` on path
14 |
15 |
16 | **What users should already know**:
17 |
18 | - How to use any SCM tool such as git or subversion
19 | - How to use APEX (obviously)
20 | - Very basic understanding of the command line
21 |
22 |
23 | **Tools/APIs we use**:
24 |
25 | Here are the pre-existing tools we used to help make these scripts
26 |
27 | *APEXExport & APEXExportSplitter*
28 |
29 | No docs for these classes but here is a quick overview discovered through trial & error and research: Export allows you to export an app from APEX into a large SQL file using the command line, and Splitter splits that large SQL file into multiple files which fit into a nice directory structure.
30 |
31 | *apex_application_install*
32 |
33 | Again there are no docs but read this blog post by Joel Kallman from Oracle on the tool http://joelkallman.blogspot.ca/2010/07/apexapplicationinstall.html. A quick overview is that essentially this comes with a bunch of pre-packaged functionality useful for installing from a file(s) generated by APEXExport & APEXExportSplitter into APEX.
34 |
35 | *Npm Scripts*
36 |
37 | Used as a front end runner for our scripts read: https://docs.npmjs.com/cli/run-script.
38 |
39 |
40 | **Scripts we create…**
41 |
42 | For each script we talk about 1. its functionality and 2. How it works. And occasionally why it’s needed if not immediately obvious.
43 |
44 | (Note: there are more scripts than this but those are mostly for style and calling from other scripts and not listed here)
45 |
46 | *...for dealing with APEX:*
47 | - file-to-apex
48 | - Converts a file directory generated by APEXExport(Splitter) into an APEX app
49 | - Uses apex_application_install to set import config data (specified in the user’s config file) such as app_alias, workspace_id, and application_id
50 | - apex-to-file
51 | - Converts an APEX app into files
52 | - Checks for proper config and then calls APEXExport & APEXExportSplitter
53 | - uninstall-apex
54 | - Uninstalls your app from APEX
55 | - Calls the delete_application and end_environment scripts generated by Splitting the file generated by APEXExport
56 |
57 | *...for user convenience:*
58 | - new-conf-file
59 | - Creates a new config file based on user input
60 | - Reduces chances of typos in config file creation and was all around convenient during the development process
61 | - Gathers user input for each config value and writes it to a file
62 | - switch-conf-file
63 | - Switches the config file being used
64 | - Was convenient and time-saving during development so I figured it would be nice to expose this functionality to the user as well
65 | - A config file is referenced by an asc.conf symlink, this script lists the available configs and changes the symlink to point to the new file of the user’s choice
66 | - generate-app-id
67 | - Generates an application ID that is unused in your copy of APEX
68 | - Solves the problem of accidentally overwriting another developers app since an unused app id can always be generated
69 | - Exposes the apex_application_install.generate_application_id functionality to the user
70 | - read-conf-file
71 | - States which config file is being used and lists the contents
72 | - Again it was nice to type a single short command rather than 2 longer ones.
73 | - readlink asc.conf && cat asc.conf
74 |
75 |
76 | **Problems faced during creation and our solutions**:
77 |
78 | *1) Application Object ids change on every export causing large conflicts in source control*
79 |
80 | We use APEX's -expOrginalIds option, and since APEX 5.0 seems to have a mechanism for dealing with conflicting Ids (tested by importing several applications using the same Object Ids) we can import into Oracle using the original Ids (is this problem even one that the user needs to know about? Since the problem basically just comes from the paper but turns out to not be an issue it seems as if we just created an issue out of nothing)
81 |
82 | *2) Can’t import into APEX without workspace_id*
83 |
84 | (Believe me, just figuring out that this was the problem without any proper docs was an entire problem of its own)
85 | We use PL/SQL to find the workspace_id (using the user input for workspace) and set the app’s workspace_id as such. Solved in file-to-apex script.
86 |
87 | *3) Possibility of overwriting another developer’s app by picking the same app_id*
88 |
89 | We create a script which automatically generates an unused app_id by exposing the functionality of apex_application_install.generate_application_id. Solved in generate-app-id.
90 |
91 | *4) App-aliases must be unique across workspace*
92 |
93 | We auto generate the app_alias using the app_id. Since the app_id must be unique this ensures that the app_alias will also be unique. We use the string ‘F’ + app_id as the alias. Solved in file-to-apex script.
94 |
95 | *5) When importing to certain servers (like prod) we want to have control over the app_alias*
96 |
97 | We add an optional app_alias value to the config file. If filled in we set the alias to the given value, otherwise we use the auto generated one described previously. Solved in file-to-apex script.
98 |
99 | *6) How to generalize (parameterize) scripts without causing source-control noise*
100 |
101 | We create config files and introduce a symlink which points to the config file which needs to be used. We then warn the user to ignore the symlink (and probably the other config files) in order to remove all possible source-control noise. Now the only noise should come the APEX app itself, that is, we are not adding any extra noise ourselves with these scripts.
102 |
103 | *7) There exists the possibility of overwriting work*
104 |
105 | Further explanation: If I were to make changes in APEX and then, without running apex-to-file, pull from the main SCM repo and run file-to-apex I would lose all my changes without any warning.
106 | Solution: The current solution is to encourage proper workflow practices with users, especially frequent committing. This falls under the “user ought to know how to use SCM” responsibility.
107 | Further Improvement: It would be possible to, after pulling from the main SCM repo run a apex-to-file, check the two versions against each other, and force the user to merge any conflicts properly.
108 |
109 | *8) Code is not easily sharable and could result in many different versions of the same code causing confusion and conflicting usage*
110 |
111 | We use npm to package the scripts as a node module.
112 |
113 |
114 |
115 |
116 | **Unsolved issues/future improvement**:
117 | *1) Random noise in app meta-data*
118 |
119 | To reproduce:
120 |
121 | - Have two developers working on their own version of an app
122 | - Developer 1 makes no change, runs apex-to-file, commits, and pushes to SCM
123 | - Developer 2 makes no changes and pulls from SCM to incorporate Developer 1’s changes
124 | - There are now conflicts shown in the merge attempt, most likely in ./apex/application/create_application.sql and some randomly generated empty sql files, despite none actually existing.
125 |
126 | Why it occurs:
127 |
128 | Every APEX app comes with meta-data; such as who last edited the app and when, what workspace ID was this last edited in, etc.; this obviously changes with every edit so SCM will always detect conflicts on every single attempt to merge.
129 |
130 | How to avoid/fix:
131 |
132 | There is no easy avoidal mechanism or fix for this issue. One possible solution is to write scripts which detect garbage conflicts and automatically deal with them; however, while some conflicts are consistent and predictable, others occur seemingly at random.
133 |
134 | *2) Deleting a page will always win merges*
135 |
136 | To reproduce:
137 |
138 | - Have two developers working on their own versions of an app (i.e. working on different features to be added).
139 | - Developer 1 deletes a page in the app and pushes to the project's repo.
140 | - Developer 2 merges developer 1's changes and decides to keep the deleted page in the merge.
141 | - When developer 2 reinstalls the app into apex the page will still be deleted.
142 |
143 | Why it occurs:
144 |
145 | Since a page was deleted, it's removed from the install.sql script generated by apex. When git sees the merge of the two developers, only one has changed the install.sql script so it automatically applies those changes to the merge meaning the page is no longer called during install so it's never created in your apex application.
146 |
147 | How to avoid/fix:
148 |
149 | Deleting a page from an app is an important decision in any development process thus you should consult with your team before doing so. If you do end up deleting a page you will have to manually re-add the install lines the install lines to the install.sql script (found in /your/project/dir/apex/install.sql).
150 |
151 | *3) Config files on top project level are kind of gross*
152 |
153 | It might be a good idea to keep the config files in a place where the user cannot easily see them. Before this can be implemented however we would need to create an `edit-conf-file` function so the user can interact with config files without ever actually needing to touch one of them (all “touching” done through our provided scripts).
154 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # apex-source-control
2 | Introducing file-based version-control for Oracle Application Express apps!
3 |
4 | * Designed to be used by teams who want to bring their experience in version-control and APEX development together
5 | * Any version-control tool can be used, not just git
6 | * Tested on Linux and OSX (Windows not supported)
7 |
8 | # Obsolete
9 | This is obsolete now that SQLcl includes the application export functionality.
10 | Running `apex export -skipExportDate -expOriginalIds -split -splitNoCheckSum -applicationid $apexappid`
11 | will give the same result except for replacing absolute paths with relative paths in the scripts for git.
12 |
13 | ## Getting Started
14 | Prerequisites:
15 | * Oracle SQLcl on the path (https://www.oracle.com/database/technologies/appdev/sqlcl.html)
16 |
17 | If you don't/can't use SQLcl, this also still supports the legacy tools from APEX 5. To use them instead of sqlcl, you require:
18 | * APEXExport.class and APEXExportSplitter.class which come with [APEX 5.0] (http://www.oracle.com/technetwork/developer-tools/apex/downloads/index.html) and above
19 | * An `export APEX_HOME` with `$APEX_HOME/utilities/oracle/apex/*.class` being the location of the above mentioned files
20 | * An installation of [Oracle Instant Client](http://www.oracle.com/technetwork/database/features/instant-client/index-100365.html)
21 | * An `export ORACLE_HOME` with an existing `$ORACLE_HOME/jdbc/lib/jdbc6.jar` (likely included in installation of Oracle Instant Client)
22 | * `sqlplus` on path
23 |
24 | ## Usage
25 | #### Bring an existing APEX app into source control
26 |
27 | 1) Make a local directory for your app and in the new directory run `npm init` and follow the given prompts
28 |
29 | 2) Add the following lines to your devDependencies in package.json (Note: delete or repurpose the pre-existing scripts value)
30 | ```
31 | "scripts": {
32 | "apex-to-file" : "apex-source-control apex-to-file",
33 | "file-to-apex" : "apex-source-control file-to-apex",
34 | "new-conf-file" : "apex-source-control new-conf-file",
35 | "switch-conf-file" : "apex-source-control switch-conf-file",
36 | "read-conf-file" : "apex-source-control read-conf-file",
37 | "generate-app-id" : "apex-source-control generate-app-id",
38 | "uninstall-apex" : "apex-source-control uninstall-apex"
39 | },
40 | ```
41 | If you want you can change the npm run commands (under scripts) to anything you'd like.
42 |
43 | 3) Run the following commands and follow the prompts. The app id, parsing_schema, workspace_name and database connection info should all correspond to the app you want to download (see Configuration)
44 | ```
45 | npm install --save-dev apex-source-control
46 | npm run new-conf-file #create a config file with the info of the app you want to download
47 | npm run switch-conf-file #unnecessary if you choose to switch to your new config file in npm run in previous command
48 | npm run apex-to-file #download the app locally
49 | ```
50 | You can now set up the application as a git or other version-control repository. Be warned that if you downloaded the app from another developer's copy of the app, or some other version of the app you don't want to overwrite, you should create a new config file and set up a new version of the application.
51 |
52 | #### Setting up from an APEX export file
53 |
54 | 1) Make a local directory for your app and in the new directory run `npm init` and follow the given prompts
55 |
56 | 2) Add the following lines to your devDependencies in package.json (Note: delete or repurpose the pre-existing scripts value)
57 | ```
58 | "scripts": {
59 | "apex-to-file" : "apex-source-control apex-to-file",
60 | "file-to-apex" : "apex-source-control file-to-apex",
61 | "new-conf-file" : "apex-source-control new-conf-file",
62 | "switch-conf-file" : "apex-source-control switch-conf-file",
63 | "read-conf-file" : "apex-source-control read-conf-file",
64 | "generate-app-id" : "apex-source-control generate-app-id",
65 | "uninstall-apex" : "apex-source-control uninstall-apex"
66 | },
67 | ```
68 | If you want you can change the npm run commands (under scripts) to anything you'd like (see npm scripts Commands).
69 |
70 | 3) Run `npm install --save-dev apex-source-control`
71 |
72 | 4) Copy the export file into your project directory
73 |
74 | 5) Set up your classpath and run APEXExportSplitter on the export file
75 | ```
76 | export CLASSPATH=$APEX_HOME/utilities:$ORACLE_HOME/jdbc/lib/ojdbc6.jar
77 | java oracle.apex.APEXExportSplitter $export_file
78 | ```
79 | The CLASSPATH variable does not need to be added to your bash profile
80 |
81 | 6) Rename the generated directory to apex/
82 |
83 | 7) cd into apex/ and run `sed -i 's^@application^@apex/application^g' install.sql`
84 |
85 | We do this because we need to set the relative path to the install components from the top level directory
86 |
87 | 8) Remove the old `$export_file` or place it in a different directory
88 |
89 | From here you can now either set up the project as a git/subversion/etc. repository or install into apex using:
90 | ```
91 | npm run new-conf-file
92 | npm run switch-conf-file #unnecessary if you choose to switch to your new config file in npm run new-conf-file
93 | npm run file-to-apex
94 | ```
95 | ## Working with existing apex-source-control project
96 |
97 | 1) Clone the repository locally
98 |
99 | 2) Use `npm install` to install dependencies
100 |
101 | 3) Run the following commands and follow the prompts. This will set up your config file and put the application into your APEX workspace
102 | ```
103 | npm run new-conf-file #create config file with the info of the app you want to use for version control
104 | npm run switch-conf-file #unnecessary if you choose to switch to your new config file in npm run new-conf-file
105 | npm run file-to-apex #download the app locally
106 | ```
107 | That's it!
108 |
109 | When you run `npm run new-conf-file` you can either enter the info of the app you are already using to develop (your version will be overwritten by the one in version control) or enter in the info of a non-existent app which will be automatically created after running `npm run file-to-apex` (see Configuration).
110 |
111 | ## npm scripts Commands
112 | Note: You can change these commands to anything you like by editing the scripts value of `package.json`.
113 | For example if you replaced `"apex-to-file" : "apex-source-control apex-to-file"` with `"atf" : "apex-source-control apex-to-file"` then your new command would be `npm run atf`.
114 | ##### npm run apex-to-file
115 | Turn your apex workspace project into a file directory suitable for version control tools.
116 | ##### npm run file-to-apex
117 | Import your file directory into apex as an apex application.
118 | Will overwrite any existing app in the same workspace with the same id.
119 |
120 | This command will only work with a $PROJECT_HOME/apex/ dir which was generated by `npm run apex-to-file` or is setup as described in steps 6 to 8 of Setting up from an APEX export file.
121 | ##### npm run uninstall-apex
122 | Uninstall your app from apex
123 | ##### npm run new-conf-file
124 | Creates a new config file using user input.
125 | ##### npm run switch-conf-file
126 | Switches the symlink to the config file of user's choice
127 | ##### npm run read-conf-file
128 | Outputs the name and contents of the config file currently being used
129 | ##### npm run generate-app-id
130 | Logs into your database and automatically generates an unused app-id.
131 | Used in order to avoid accidentaly overwritting someone else's app.
132 | Can only be run if your config file is set up with proper database login info (see Config file examples).
133 | ###Workflow & Project Sanitation
134 | * Ignore config files in version control (.gitignore for git) since you'll likely not want to share login info in version control.
135 | If you want to leave the configs in version control then you should at least ignore the asc.conf symlink to avoid unnecessary noise
136 | * Any non apex files you wish to put into version control along with your apex app should be placed in a project-top-level dir called non-apex
137 | * After merging your code you should `npm run file-to-apex` and test that the merge didn't break anything
138 | If you have automated tests you can just run those instead
139 | * It is good practice to start your day with a merge
140 |
141 | ## Configuration
142 | Config files are placed in a top level config/ directory.
143 | Each developer has their own config file with their app data which is then refrenced by a symlink named `asc.conf` (short for apex-source-control.conf).
144 | Config files should not be put under version control (unless you want to share connection data for some reason).
145 | ##### apexappid
146 | The unique application id # of your APEX app in Oracle.
147 | Used to tell APEX which application to export.
148 |
149 | The application id does not have to already exist in APEX in order to be installed by `npm run file-to-apex` but must not conflict with an app id in a different workspace.
150 | It can be the same as a pre-existing APEX app in the same workspace, but be careful about overwriting work that isn't your own.
151 | ##### workspace_name
152 | Name of the workspace where the app is installed or is to be installed to.
153 | The workspace should already exist before usage
154 | ##### parsing_schema
155 | The parsing_schema used by APEX for this app.
156 | If set incorrectly the app may not function at all when imported into APEX.
157 | ##### app_alias
158 | The app alias to be used by APEX. Should usually not be set.
159 |
160 | Since aliases must be unique within a workspace (and recommended to be unique within an instance) this should only be set for important versions of the app (i.e. production or dev versions).
161 | If this field is left blank an app_alias will be auto-generated ('F' + $apexappid) to avoid conflicts.
162 | ##### database_connection
163 | The database_connection info in [JDBC](http://www.orafaq.com/wiki/JDBC) format, i.e. Hostname:Port/SID. Example: `myhost:1521/orcl`.
164 | Used in connect statements such as `sqlplus $username/$password@$database_connection`
165 | ##### username
166 | Username of database login
167 | ##### password
168 | Password of database login
169 | #### Config file examples
170 | A normal developer config file
171 | ```
172 | apexappid=116
173 | workspace_name=TEST_WORKSPACE
174 | parsing_schema=PARSER
175 | app_alias=
176 | database_connection=localhost:1521/xe
177 | username=the_coolest_guy
178 | password=no_really_the_coolest
179 | ```
180 | A config file for using `npm run generate-app-id`
181 | ```
182 | apexappid=
183 | workspace_name=
184 | parsing_schema=
185 | app_alias=
186 | database_connection=localhost:1521/xe
187 | username=the_coolest_guy
188 | password=no_really_the_coolest
189 | ```
190 | A config file for a production version of an app
191 | ```
192 | apexappid=113
193 | workspace_name=PROD_APPS
194 | parsing_schema=PARSER
195 | app_alias=Hello_World
196 | database_connection=localhost:1521/xe
197 | username=i_wanna_be_the_very_best
198 | password=that_no_one_ever_was
199 | ```
200 | ###Known Issues
201 | #### Deleting a page will always win merges
202 | **To Reproduce**:
203 | * Have two developers working on different versions of an app (i.e. working on different features to be added).
204 | * Developer 1 deletes a page in the app and pushes to the project's repo.
205 | * Developer 2 merges developer 1's changes and decides to keep the deleted page in the merge.
206 | * When developer 2 reinstalls the app into apex the page will still be deleted.
207 |
208 | **Why it occurs**:
209 |
210 | Since a page was deleted, it's removed from the install.sql script generated by apex. When git sees the merge of the two developers, only one has changed the install.sql script so it automatically applies those changes to the merge meaning the page is no longer called during install so it's never created in your apex application.
211 |
212 | **How to avoid**:
213 |
214 | Be extremely careful when deleting pages and consult with your teammates first
215 |
216 | **How to fix**:
217 |
218 | If you do end up accidently deleting a page then you will have to manually re-add the install lines to the install.sql
219 |
220 | #### Random version control noise in application meta-data
221 | On every commit there will be conflicts within the create_application.sql (and likely some others) which will have to be resolved by hand.
222 | Unfortunately there is no easy way to avoid this, but as you continue to use this tool you'll be able to quickly identify which files have real changes and which are garbage.
223 |
224 | ## Inspiration
225 | These scripts were designed using [this paper] (http://www.rwijk.nl/AboutOracle/psdua.pdf) as reference.
226 | There's a lot of good information about directory structure and general developer workflow so it's definitely worth a read.
227 |
228 | It should be noted that if you decide to read the paper we have changed the names/functions of the scripts slightly: file-to-apex=install_apex.sql; uninstall-apex=uninstall_apex.sql; and apex-to-file=apexupdate.sh (Except we don't auto-update using subversion in order to leave more user freedom)
229 |
230 | ## Developers
231 | To release:
232 |
233 | - update the version in package.json
234 | - tag with matching tag. E.g. `git tag -a v1.3.2`
235 | - deploy to npm repo `npm publish`
236 |
237 |
--------------------------------------------------------------------------------
/apex-source-control:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | function main {
4 | case "${1}" in
5 | 'test')
6 | ./scripts/check_conf_file.sh
7 | ;;
8 | 'apex-to-file')
9 | apex_to_file
10 | ;;
11 | 'file-to-apex')
12 | file_to_apex
13 | ;;
14 | 'new-conf-file')
15 | new_conf_file
16 | ;;
17 | 'switch-conf-file')
18 | switch_conf_file
19 | ;;
20 | 'read-conf-file')
21 | read_conf_file
22 | ;;
23 | 'generate-app-id')
24 | generate_app_id
25 | ;;
26 | 'uninstall-apex')
27 | uninstall_apex
28 | ;;
29 | get-connect-string|connect-string)
30 | get_connect_string
31 | ;;
32 | *)
33 | echo "apex-source-control: bad command"
34 | ;;
35 | esac
36 | }
37 |
38 | function die {
39 | echo $@
40 | exit 1
41 | }
42 |
43 | function upcase {
44 | echo "$@" | tr '[a-z-]' '[A-Z_]'
45 | }
46 |
47 | function get_connect_string {
48 | source ./config/asc.conf
49 | local connect_string="${username}/${password}@${database_connection}"
50 | echo "${connect_string}"
51 | }
52 |
53 |
54 | function run_sql_cmd {
55 | local connect_string="$(get_connect_string)"
56 | local sql_cmd
57 | if which sql > /dev/null; then
58 | echo Running PWD $PWD
59 | sql_cmd="sql -S"
60 | else
61 | echo WARNING: could not find SQLcl \(sql\). Falling back to sqlplus
62 | sql_cmd="sqlplus -S"
63 | fi
64 |
65 | NLS_LANG=.AL32UTF8
66 | export NLS_LANG
67 |
68 | ${sql_cmd} ${connect_string} "$@" || die Failed: ${sql_cmd} ${connect_string} "$@"
69 | }
70 |
71 | function check_conf_file {
72 | if [ ! -e ./config/asc.conf ]; then
73 | echo "Missing or broken symbolic link: ${PWD}/config/asc.conf"
74 | echo "Please use the command 'npm run switch-conf-file' to create the symbolic link ./config/asc.conf to your config file"
75 | echo "If you don't have a config file set up you can create one using 'npm run new-config-file'"
76 | exit 1
77 | fi
78 |
79 | echo "Using the config file at: $(readlink config/asc.conf)"
80 |
81 | source ./config/asc.conf
82 |
83 | [ -z "${apexappid}" ] && die "Missing config: ${apexappid} apexappid"
84 | [ -z "${workspace_name}" ] && die "Missing config: ${workspace_name} workspace_name"
85 | [ -z "${database_connection}" ] && die "Missing config: ${database_connection} database_connection"
86 | [ -z "${username}" ] && die "Missing config: ${username} username"
87 | [ -z "${password}" ] && die "Missing config: ${password} password"
88 |
89 | echo "Config file looks good! Moving on to the next step..."
90 | }
91 |
92 | function legacy_apex_export {
93 |
94 | [ -z "${ORACLE_HOME}" ] && die "Missing environment variable: ORACLE_HOME. Please add the path of your oracle installation to your environment variables under the variable name ORACLE_HOME"
95 | [ -z "${APEX_HOME}" ] && die "Missing environment variable: APEX_HOME. Please add the path of your apex installation to your environment variables under the variable name APEX_HOME. Note: You should be using APEX version 5 or above"
96 | [ ! -e "${ORACLE_HOME}"/jdbc/lib/ojdbc6.jar ] && die "Missing ojdbc6.jar: please download from oracle and put in ${ORACLE_HOME}/jdbc/lib directory"
97 | [ ! -e "${APEX_HOME}"/utilities/oracle/apex/APEXExport.class ] && die "Missing APEXExport class. Please ensure you are using Apex 5 or above and have the APEXExport and APEXExportSplitter classes are in the $APEX_HOME/utilities/oracle/apex/ directory"
98 | [ ! -e "${APEX_HOME}"/utilities/oracle/apex/APEXExportSplitter.class ] && die "Missing APEXExportSplitter class. Please ensure you are using Apex 5 or above and have the APEXExport and APEXExportSplitter classes are in the $APEX_HOME/utilities/oracle/apex/ directory"
99 |
100 | source ./config/asc.conf
101 |
102 | export CLASSPATH="${APEX_HOME}"/utilities:"${ORACLE_HOME}"/jdbc/lib/ojdbc6.jar
103 |
104 | export_file="f${apexappid}.sql"
105 |
106 | if [ -d apex/ ]; then
107 | rm -r apex/
108 | fi
109 | if [ -e "${export_file}" ]; then
110 | rm "${export_file}"
111 | fi
112 |
113 | java oracle.apex.APEXExport -db "${database_connection}" -user "${username}" -password "${password}" -applicationid "${apexappid}" -skipExportDate -expOriginalIds ||
114 | die "Exit code #: $?. An error has occured while trying to use APEXExport. Please check that your database_connection, username, password, and apexappid variables are all set correctly."
115 |
116 | java oracle.apex.APEXExportSplitter "${export_file}" ||
117 | die "Exit code #: $?. An error has occured while trying to use APEXExportSplitter. Please check that your apexappid variable is set correctly and that the application exists in the workspace you are trying to export from"
118 |
119 | rm "${export_file}"
120 |
121 | mv "f${apexappid}" apex #
122 |
123 | perl -pi -e 's^\@application^\@apex/application^' apex/install.sql
124 | }
125 |
126 | function apex_export {
127 | if which sql > /dev/null; then
128 | source ./config/asc.conf
129 | echo Using sqlcl to export app ${apexappid}
130 | export_file="f${apexappid}.sql"
131 |
132 | if [ -d apex/ ]; then
133 | rm -r apex/
134 | fi
135 | if [ -e "${export_file}" ]; then
136 | rm "${export_file}"
137 | fi
138 |
139 | run_sql_cmd @/dev/stdin < p_workspace_name);
183 | APEX_APPLICATION_INSTALL.SET_WORKSPACE_ID ( l_workspace_id );
184 |
185 | IF p_offset IS NOT NULL THEN
186 | apex_application_install.set_offset( p_offset );
187 | ELSE
188 | apex_application_install.generate_offset;
189 | END IF;
190 | end;
191 | /
192 | @apex/install.sql
193 | /
194 | quit
195 | EOF
196 |
197 | }
198 |
199 | function generate_app_id {
200 | source config/asc.conf || die
201 |
202 | tmpfile=$(mktemp -t generate_app_id)
203 |
204 | run_sql_cmd @/dev/stdin < ${tmpfile} || exit 1
205 | set serveroutput on
206 | set feedback off
207 | begin
208 | apex_application_install.generate_application_id;
209 | dbms_output.put_Line(apex_application_install.get_application_id);
210 | end;
211 | /
212 | exit
213 | ENDSQL
214 |
215 | app_id=$(cat $tmpfile)
216 |
217 | rm $tmpfile
218 |
219 | if [ -h config/asc.conf ]; then
220 | conf_file=$(readlink ./config/asc.conf)
221 | echo -n "The id '${app_id}' will be written to '${conf_file}'. Is this alright? [y/N]: "
222 | read can_write
223 |
224 | if [ "${can_write}" == "y" ]; then
225 | perl -pi -e "s/^apexappid=.*/apexappid=${app_id}/" config/${conf_file}
226 | echo "apexappid in '${conf_file}' has been replaced with '${app_id}'. The new config file looks like this: "
227 | cat config/${conf_file}
228 | else
229 | echo -n "The generated app id was not written to file. "
230 | echo "You can change this manually by changing the apexappid of your config to '${app_id}'"
231 | fi
232 | fi
233 |
234 | }
235 |
236 | function new_conf_file {
237 | echo "Creating new config file..."
238 |
239 | echo -n "Please enter the file name of your config file: "
240 | read conf_file
241 | if [ -z "${conf_file}" ]; then
242 | echo "Please input a value for your config file name before pressing enter"; exit 1
243 | fi
244 |
245 | if [ -e ./config/"${conf_file}" ]; then
246 | echo "Sorry, the file ./scripts/${conf_file} already exists. Either delete the existing file or choose a different name and try again."; exit 1
247 | fi
248 |
249 | echo -n "Please enter the apexappid you would like to use. This should be chosen very carefully to avoid conflicts with other developers' app ids: "
250 | read apexappid
251 |
252 | echo -n "Please enter the name of your workspace: "
253 | read workspace_name
254 |
255 | echo -n "Please enter the parsing schema for the app you are using. Note that parsing schema should be all caps: "
256 | read parsing_schema
257 |
258 | echo "NOTE: The app_alias variable should only be set for well known versions of the app (i.e. production or some dev versions) in order to avoid potentially damaging conflicts. Press [ENTER] to leave the variable unset"
259 | echo -n "Please enter the app_alias for your app: "
260 | read app_alias
261 |
262 | echo -n "Please enter your Apex database connection in the following format [Hostname:port/SID]: "
263 | read database_connection
264 |
265 | echo -n "Please enter your username for the given database: "
266 | read username
267 |
268 | echo -n "Please enter your password: "
269 | read password
270 |
271 | if [ ! -d ./config/ ]; then
272 | mkdir config
273 | fi
274 |
275 | echo "apexappid=${apexappid}" > ./config/"${conf_file}"
276 | echo "workspace_name=${workspace_name}" >> ./config/"${conf_file}"
277 | echo "parsing_schema=${parsing_schema}" >> ./config/"${conf_file}"
278 | echo "app_alias=${app_alias}" >> ./config/"${conf_file}"
279 | echo "database_connection=${database_connection}" >> ./config/"${conf_file}"
280 | echo "username=${username}" >> ./config/"${conf_file}"
281 | echo "password=${password}" >> ./config/"${conf_file}"
282 |
283 | echo "Config file successfully generated! It looks like this:"
284 |
285 | cat ./config/"${conf_file}"
286 |
287 | echo "If anything looks wrong you can simply edit the file yourself at ./config/${conf_file}"
288 |
289 | echo
290 |
291 | echo -n "Would you like to switch to the new config file now [y/n]: "
292 | read switch_bool
293 |
294 | if [ "${switch_bool}" == "y" ]; then
295 | cd config
296 | if [ -h asc.conf ]; then
297 | rm asc.conf
298 | fi
299 | ln -s "${conf_file}" asc.conf
300 | cd ..
301 | echo "./config/asc.conf now points to ./config/$( readlink ./config/asc.conf )"
302 | else
303 | echo "Config file was not switched. Run 'npm run switch-conf-file' if you would like to change this."
304 | fi
305 | }
306 |
307 | function switch_conf_file {
308 | #!/bin/bash
309 | #
310 | # This script is designed to be called from the top level directory of your project and to be placed in the ./scripts/ directory
311 |
312 | echo "The availible config files are:"
313 |
314 | ls ./config/ | sed s/asc.conf// | sed -n '1!p' #print all conf files
315 |
316 | cd config
317 |
318 | if [ -z "${1}" ]; then
319 | echo -n "Please enter the config file you would like to use: "
320 | read conf_file
321 | else
322 | conf_file="${1}"
323 | fi
324 |
325 | if [ ! -e "${conf_file}" ]; then
326 | echo "Sorry, the file ./scripts/"${conf_file}" does not exist. Either create the file using npm run new-conf-file or choose a pre-existing config file."; exit 1
327 | fi
328 |
329 | if [ -h asc.conf ]; then
330 | rm asc.conf
331 | fi
332 |
333 | ln -s "${conf_file}" asc.conf
334 |
335 | cd ..
336 |
337 | echo "./config/asc.conf now points to ./config/$( readlink ./config/asc.conf )"
338 |
339 | echo "The new config file looks like this: "
340 |
341 | cat ./config/asc.conf
342 | }
343 |
344 | function unistall_apex {
345 | check_conf_file || die
346 | source config/asc.conf || exit 1
347 |
348 | run_sql_cmd @/dev/stdin "${apexappid}" "${workspace_name}" "${parsing_schema}" < p_workspace_name );
357 | apex_application_install.set_schema( p_parsing_schema );
358 | APEX_APPLICATION_INSTALL.SET_WORKSPACE_ID ( l_workspace_id );
359 | end;
360 | /
361 | @apex/application/init.sql
362 | @apex/application/set_environment.sql
363 | @apex/application/delete_application.sql
364 | @apex/application/end_environment.sql
365 | /
366 | quit
367 |
368 | EOF
369 | }
370 |
371 | # WIPMB is this useful? Can we delete it?
372 | function read_conf_file {
373 |
374 | if [ ! -e ./config/asc.conf ]; then
375 | echo "Missing or broken symbolic link: ${PWD}/config/asc.conf"
376 | echo "Please use the command 'npm run switch-conf-file' to create the symbolic link ./config/asc.conf to your config file"
377 | echo "If you don't have a config file set up you can create one using 'npm run new-config-file'"
378 | exit 1
379 | fi
380 |
381 | echo "The config file currently being used is: "
382 | readlink ./config/asc.conf
383 |
384 | echo
385 |
386 | echo "The config file looks like this: "
387 | cat ./config/asc.conf
388 |
389 | echo "If any of the data looks wrong you can simply edit the file yourself at ./config/$(readlink ./config/asc.conf)"
390 | }
391 |
392 |
393 | main "$@"
394 |
--------------------------------------------------------------------------------